164 |
194 |
165 /** |
195 /** |
166 * Member function for returning an iterator pointing to the specified index. |
196 * Member function for returning an iterator pointing to the specified index. |
167 */ |
197 */ |
168 struct cx_iterator_s (*iterator)( |
198 struct cx_iterator_s (*iterator)( |
169 struct cx_list_s const *list, |
199 const struct cx_list_s *list, |
170 size_t index, |
200 size_t index, |
171 bool backward |
201 bool backward |
172 ); |
202 ); |
173 }; |
203 }; |
174 |
204 |
175 /** |
205 /** |
|
206 * Default implementation of an array insert. |
|
207 * |
|
208 * This function uses the element insert function for each element of the array. |
|
209 * |
|
210 * Use this in your own list class if you do not want to implement an optimized |
|
211 * version for your list. |
|
212 * |
|
213 * @param list the list |
|
214 * @param index the index where to insert the data |
|
215 * @param data a pointer to the array of data to insert |
|
216 * @param n the number of elements to insert |
|
217 * @return the number of elements actually inserted |
|
218 */ |
|
219 cx_attr_nonnull |
|
220 cx_attr_export |
|
221 size_t cx_list_default_insert_array( |
|
222 struct cx_list_s *list, |
|
223 size_t index, |
|
224 const void *data, |
|
225 size_t n |
|
226 ); |
|
227 |
|
228 /** |
|
229 * Default implementation of a sorted insert. |
|
230 * |
|
231 * This function uses the array insert function to insert consecutive groups |
|
232 * of sorted data. |
|
233 * |
|
234 * The source data @em must already be sorted wrt. the list's compare function. |
|
235 * |
|
236 * Use this in your own list class if you do not want to implement an optimized |
|
237 * version for your list. |
|
238 * |
|
239 * @param list the list |
|
240 * @param sorted_data a pointer to the array of pre-sorted data to insert |
|
241 * @param n the number of elements to insert |
|
242 * @return the number of elements actually inserted |
|
243 */ |
|
244 cx_attr_nonnull |
|
245 cx_attr_export |
|
246 size_t cx_list_default_insert_sorted( |
|
247 struct cx_list_s *list, |
|
248 const void *sorted_data, |
|
249 size_t n |
|
250 ); |
|
251 |
|
252 /** |
|
253 * Default unoptimized sort implementation. |
|
254 * |
|
255 * This function will copy all data to an array, sort the array with standard |
|
256 * qsort, and then copy the data back to the list memory. |
|
257 * |
|
258 * Use this in your own list class if you do not want to implement an optimized |
|
259 * version for your list. |
|
260 * |
|
261 * @param list the list that shall be sorted |
|
262 */ |
|
263 cx_attr_nonnull |
|
264 cx_attr_export |
|
265 void cx_list_default_sort(struct cx_list_s *list); |
|
266 |
|
267 /** |
|
268 * Default unoptimized swap implementation. |
|
269 * |
|
270 * Use this in your own list class if you do not want to implement an optimized |
|
271 * version for your list. |
|
272 * |
|
273 * @param list the list in which to swap |
|
274 * @param i index of one element |
|
275 * @param j index of the other element |
|
276 * @retval zero success |
|
277 * @retval non-zero when indices are out of bounds or memory |
|
278 * allocation for the temporary buffer fails |
|
279 */ |
|
280 cx_attr_nonnull |
|
281 cx_attr_export |
|
282 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); |
|
283 |
|
284 /** |
|
285 * Initializes a list struct. |
|
286 * |
|
287 * Only use this function if you are creating your own list implementation. |
|
288 * The purpose of this function is to be called in the initialization code |
|
289 * of your list, to set certain members correctly. |
|
290 * |
|
291 * This is particularly important when you want your list to support |
|
292 * #CX_STORE_POINTERS as @p elem_size. This function will wrap the list |
|
293 * class accordingly and make sure that you can implement your list as if |
|
294 * it was only storing objects and the wrapper will automatically enable |
|
295 * the feature of storing pointers. |
|
296 * |
|
297 * @par Example |
|
298 * |
|
299 * @code |
|
300 * CxList *myCustomListCreate( |
|
301 * const CxAllocator *allocator, |
|
302 * cx_compare_func comparator, |
|
303 * size_t elem_size |
|
304 * ) { |
|
305 * if (allocator == NULL) { |
|
306 * allocator = cxDefaultAllocator; |
|
307 * } |
|
308 * |
|
309 * MyCustomList *list = cxCalloc(allocator, 1, sizeof(MyCustomList)); |
|
310 * if (list == NULL) return NULL; |
|
311 * |
|
312 * // initialize |
|
313 * cx_list_init((CxList*)list, &my_custom_list_class, |
|
314 * allocator, comparator, elem_size); |
|
315 * |
|
316 * // ... some more custom stuff ... |
|
317 * |
|
318 * return (CxList *) list; |
|
319 * } |
|
320 * @endcode |
|
321 * |
|
322 * @param list the list to initialize |
|
323 * @param cl the list class |
|
324 * @param allocator the allocator for the elements |
|
325 * @param comparator a compare function for the elements |
|
326 * @param elem_size the size of one element |
|
327 */ |
|
328 cx_attr_nonnull_arg(1, 2, 3) |
|
329 cx_attr_export |
|
330 void cx_list_init( |
|
331 struct cx_list_s *list, |
|
332 struct cx_list_class_s *cl, |
|
333 const struct cx_allocator_s *allocator, |
|
334 cx_compare_func comparator, |
|
335 size_t elem_size |
|
336 ); |
|
337 |
|
338 /** |
176 * Common type for all list implementations. |
339 * Common type for all list implementations. |
177 */ |
340 */ |
178 typedef struct cx_list_s CxList; |
341 typedef struct cx_list_s CxList; |
179 |
342 |
180 /** |
343 /** |
181 * Advises the list to store copies of the objects (default mode of operation). |
|
182 * |
|
183 * Retrieving objects from this list will yield pointers to the copies stored |
|
184 * within this list. |
|
185 * |
|
186 * @param list the list |
|
187 * @see cxListStorePointers() |
|
188 */ |
|
189 __attribute__((__nonnull__)) |
|
190 void cxListStoreObjects(CxList *list); |
|
191 |
|
192 /** |
|
193 * Advises the list to only store pointers to the objects. |
|
194 * |
|
195 * Retrieving objects from this list will yield the original pointers stored. |
|
196 * |
|
197 * @note This function forcibly sets the element size to the size of a pointer. |
|
198 * Invoking this function on a non-empty list that already stores copies of |
|
199 * objects is undefined. |
|
200 * |
|
201 * @param list the list |
|
202 * @see cxListStoreObjects() |
|
203 */ |
|
204 __attribute__((__nonnull__)) |
|
205 void cxListStorePointers(CxList *list); |
|
206 |
|
207 /** |
|
208 * Returns true, if this list is storing pointers instead of the actual data. |
|
209 * |
|
210 * @param list |
|
211 * @return true, if this list is storing pointers |
|
212 * @see cxListStorePointers() |
|
213 */ |
|
214 __attribute__((__nonnull__)) |
|
215 static inline bool cxListIsStoringPointers(CxList const *list) { |
|
216 return list->store_pointer; |
|
217 } |
|
218 |
|
219 /** |
|
220 * Returns the number of elements currently stored in the list. |
344 * Returns the number of elements currently stored in the list. |
221 * |
345 * |
222 * @param list the list |
346 * @param list the list |
223 * @return the number of currently stored elements |
347 * @return the number of currently stored elements |
224 */ |
348 */ |
225 __attribute__((__nonnull__)) |
349 cx_attr_nonnull |
226 static inline size_t cxListSize(CxList const *list) { |
350 static inline size_t cxListSize(const CxList *list) { |
227 return list->size; |
351 return list->collection.size; |
228 } |
352 } |
229 |
353 |
230 /** |
354 /** |
231 * Adds an item to the end of the list. |
355 * Adds an item to the end of the list. |
232 * |
356 * |
233 * @param list the list |
357 * @param list the list |
234 * @param elem a pointer to the element to add |
358 * @param elem a pointer to the element to add |
235 * @return zero on success, non-zero on memory allocation failure |
359 * @retval zero success |
|
360 * @retval non-zero memory allocation failure |
236 * @see cxListAddArray() |
361 * @see cxListAddArray() |
237 */ |
362 */ |
238 __attribute__((__nonnull__)) |
363 cx_attr_nonnull |
239 static inline int cxListAdd( |
364 static inline int cxListAdd( |
240 CxList *list, |
365 CxList *list, |
241 void const *elem |
366 const void *elem |
242 ) { |
367 ) { |
243 return list->cl->insert_element(list, list->size, elem); |
368 list->collection.sorted = false; |
|
369 return list->cl->insert_element(list, list->collection.size, elem); |
244 } |
370 } |
245 |
371 |
246 /** |
372 /** |
247 * Adds multiple items to the end of the list. |
373 * Adds multiple items to the end of the list. |
248 * |
374 * |
249 * This method is more efficient than invoking cxListAdd() multiple times. |
375 * This method is more efficient than invoking cxListAdd() multiple times. |
250 * |
376 * |
251 * If there is not enough memory to add all elements, the returned value is |
377 * If there is not enough memory to add all elements, the returned value is |
252 * less than \p n. |
378 * less than @p n. |
253 * |
379 * |
254 * If this list is storing pointers instead of objects \p array is expected to |
380 * If this list is storing pointers instead of objects @p array is expected to |
255 * be an array of pointers. |
381 * be an array of pointers. |
256 * |
382 * |
257 * @param list the list |
383 * @param list the list |
258 * @param array a pointer to the elements to add |
384 * @param array a pointer to the elements to add |
259 * @param n the number of elements to add |
385 * @param n the number of elements to add |
260 * @return the number of added elements |
386 * @return the number of added elements |
261 */ |
387 */ |
262 __attribute__((__nonnull__)) |
388 cx_attr_nonnull |
263 static inline size_t cxListAddArray( |
389 static inline size_t cxListAddArray( |
264 CxList *list, |
390 CxList *list, |
265 void const *array, |
391 const void *array, |
266 size_t n |
392 size_t n |
267 ) { |
393 ) { |
268 return list->cl->insert_array(list, list->size, array, n); |
394 list->collection.sorted = false; |
|
395 return list->cl->insert_array(list, list->collection.size, array, n); |
269 } |
396 } |
270 |
397 |
271 /** |
398 /** |
272 * Inserts an item at the specified index. |
399 * Inserts an item at the specified index. |
273 * |
400 * |
274 * If \p index equals the list \c size, this is effectively cxListAdd(). |
401 * If @p index equals the list @c size, this is effectively cxListAdd(). |
275 * |
402 * |
276 * @param list the list |
403 * @param list the list |
277 * @param index the index the element shall have |
404 * @param index the index the element shall have |
278 * @param elem a pointer to the element to add |
405 * @param elem a pointer to the element to add |
279 * @return zero on success, non-zero on memory allocation failure |
406 * @retval zero success |
280 * or when the index is out of bounds |
407 * @retval non-zero memory allocation failure or the index is out of bounds |
281 * @see cxListInsertAfter() |
408 * @see cxListInsertAfter() |
282 * @see cxListInsertBefore() |
409 * @see cxListInsertBefore() |
283 */ |
410 */ |
284 __attribute__((__nonnull__)) |
411 cx_attr_nonnull |
285 static inline int cxListInsert( |
412 static inline int cxListInsert( |
286 CxList *list, |
413 CxList *list, |
287 size_t index, |
414 size_t index, |
288 void const *elem |
415 const void *elem |
289 ) { |
416 ) { |
|
417 list->collection.sorted = false; |
290 return list->cl->insert_element(list, index, elem); |
418 return list->cl->insert_element(list, index, elem); |
291 } |
419 } |
292 |
420 |
293 /** |
421 /** |
|
422 * Inserts an item into a sorted list. |
|
423 * |
|
424 * If the list is not sorted already, the behavior is undefined. |
|
425 * |
|
426 * @param list the list |
|
427 * @param elem a pointer to the element to add |
|
428 * @retval zero success |
|
429 * @retval non-zero memory allocation failure |
|
430 */ |
|
431 cx_attr_nonnull |
|
432 static inline int cxListInsertSorted( |
|
433 CxList *list, |
|
434 const void *elem |
|
435 ) { |
|
436 list->collection.sorted = true; // guaranteed by definition |
|
437 const void *data = list->collection.store_pointer ? &elem : elem; |
|
438 return list->cl->insert_sorted(list, data, 1) == 0; |
|
439 } |
|
440 |
|
441 /** |
294 * Inserts multiple items to the list at the specified index. |
442 * Inserts multiple items to the list at the specified index. |
295 * If \p index equals the list size, this is effectively cxListAddArray(). |
443 * If @p index equals the list size, this is effectively cxListAddArray(). |
296 * |
444 * |
297 * This method is usually more efficient than invoking cxListInsert() |
445 * This method is usually more efficient than invoking cxListInsert() |
298 * multiple times. |
446 * multiple times. |
299 * |
447 * |
300 * If there is not enough memory to add all elements, the returned value is |
448 * If there is not enough memory to add all elements, the returned value is |
301 * less than \p n. |
449 * less than @p n. |
302 * |
450 * |
303 * If this list is storing pointers instead of objects \p array is expected to |
451 * If this list is storing pointers instead of objects @p array is expected to |
304 * be an array of pointers. |
452 * be an array of pointers. |
305 * |
453 * |
306 * @param list the list |
454 * @param list the list |
307 * @param index the index where to add the elements |
455 * @param index the index where to add the elements |
308 * @param array a pointer to the elements to add |
456 * @param array a pointer to the elements to add |
309 * @param n the number of elements to add |
457 * @param n the number of elements to add |
310 * @return the number of added elements |
458 * @return the number of added elements |
311 */ |
459 */ |
312 __attribute__((__nonnull__)) |
460 cx_attr_nonnull |
313 static inline size_t cxListInsertArray( |
461 static inline size_t cxListInsertArray( |
314 CxList *list, |
462 CxList *list, |
315 size_t index, |
463 size_t index, |
316 void const *array, |
464 const void *array, |
317 size_t n |
465 size_t n |
318 ) { |
466 ) { |
|
467 list->collection.sorted = false; |
319 return list->cl->insert_array(list, index, array, n); |
468 return list->cl->insert_array(list, index, array, n); |
|
469 } |
|
470 |
|
471 /** |
|
472 * Inserts a sorted array into a sorted list. |
|
473 * |
|
474 * This method is usually more efficient than inserting each element separately, |
|
475 * because consecutive chunks of sorted data are inserted in one pass. |
|
476 * |
|
477 * If there is not enough memory to add all elements, the returned value is |
|
478 * less than @p n. |
|
479 * |
|
480 * If this list is storing pointers instead of objects @p array is expected to |
|
481 * be an array of pointers. |
|
482 * |
|
483 * If the list is not sorted already, the behavior is undefined. |
|
484 * |
|
485 * @param list the list |
|
486 * @param array a pointer to the elements to add |
|
487 * @param n the number of elements to add |
|
488 * @return the number of added elements |
|
489 */ |
|
490 cx_attr_nonnull |
|
491 static inline size_t cxListInsertSortedArray( |
|
492 CxList *list, |
|
493 const void *array, |
|
494 size_t n |
|
495 ) { |
|
496 list->collection.sorted = true; // guaranteed by definition |
|
497 return list->cl->insert_sorted(list, array, n); |
320 } |
498 } |
321 |
499 |
322 /** |
500 /** |
323 * Inserts an element after the current location of the specified iterator. |
501 * Inserts an element after the current location of the specified iterator. |
324 * |
502 * |
325 * The used iterator remains operational, but all other active iterators should |
503 * The used iterator remains operational, but all other active iterators should |
326 * be considered invalidated. |
504 * be considered invalidated. |
327 * |
505 * |
328 * If \p iter is not a list iterator, the behavior is undefined. |
506 * If @p iter is not a list iterator, the behavior is undefined. |
329 * If \p iter is a past-the-end iterator, the new element gets appended to the list. |
507 * If @p iter is a past-the-end iterator, the new element gets appended to the list. |
330 * |
508 * |
331 * @param iter an iterator |
509 * @param iter an iterator |
332 * @param elem the element to insert |
510 * @param elem the element to insert |
333 * @return zero on success, non-zero on memory allocation failure |
511 * @retval zero success |
|
512 * @retval non-zero memory allocation failure |
334 * @see cxListInsert() |
513 * @see cxListInsert() |
335 * @see cxListInsertBefore() |
514 * @see cxListInsertBefore() |
336 */ |
515 */ |
337 __attribute__((__nonnull__)) |
516 cx_attr_nonnull |
338 static inline int cxListInsertAfter( |
517 static inline int cxListInsertAfter( |
339 CxMutIterator *iter, |
518 CxIterator *iter, |
340 void const *elem |
519 const void *elem |
341 ) { |
520 ) { |
342 return ((struct cx_list_s *) iter->src_handle)->cl->insert_iter(iter, elem, 0); |
521 CxList* list = (CxList*)iter->src_handle.m; |
|
522 list->collection.sorted = false; |
|
523 return list->cl->insert_iter(iter, elem, 0); |
343 } |
524 } |
344 |
525 |
345 /** |
526 /** |
346 * Inserts an element before the current location of the specified iterator. |
527 * Inserts an element before the current location of the specified iterator. |
347 * |
528 * |
348 * The used iterator remains operational, but all other active iterators should |
529 * The used iterator remains operational, but all other active iterators should |
349 * be considered invalidated. |
530 * be considered invalidated. |
350 * |
531 * |
351 * If \p iter is not a list iterator, the behavior is undefined. |
532 * If @p iter is not a list iterator, the behavior is undefined. |
352 * If \p iter is a past-the-end iterator, the new element gets appended to the list. |
533 * If @p iter is a past-the-end iterator, the new element gets appended to the list. |
353 * |
534 * |
354 * @param iter an iterator |
535 * @param iter an iterator |
355 * @param elem the element to insert |
536 * @param elem the element to insert |
356 * @return zero on success, non-zero on memory allocation failure |
537 * @retval zero success |
|
538 * @retval non-zero memory allocation failure |
357 * @see cxListInsert() |
539 * @see cxListInsert() |
358 * @see cxListInsertAfter() |
540 * @see cxListInsertAfter() |
359 */ |
541 */ |
360 __attribute__((__nonnull__)) |
542 cx_attr_nonnull |
361 static inline int cxListInsertBefore( |
543 static inline int cxListInsertBefore( |
362 CxMutIterator *iter, |
544 CxIterator *iter, |
363 void const *elem |
545 const void *elem |
364 ) { |
546 ) { |
365 return ((struct cx_list_s *) iter->src_handle)->cl->insert_iter(iter, elem, 1); |
547 CxList* list = (CxList*)iter->src_handle.m; |
|
548 list->collection.sorted = false; |
|
549 return list->cl->insert_iter(iter, elem, 1); |
366 } |
550 } |
367 |
551 |
368 /** |
552 /** |
369 * Removes the element at the specified index. |
553 * Removes the element at the specified index. |
370 * |
554 * |
371 * If an element destructor function is specified, it is called before |
555 * If an element destructor function is specified, it is called before |
372 * removing the element. |
556 * removing the element. |
373 * |
557 * |
374 * @param list the list |
558 * @param list the list |
375 * @param index the index of the element |
559 * @param index the index of the element |
376 * @return zero on success, non-zero if the index is out of bounds |
560 * @retval zero success |
377 */ |
561 * @retval non-zero index out of bounds |
378 __attribute__((__nonnull__)) |
562 */ |
|
563 cx_attr_nonnull |
379 static inline int cxListRemove( |
564 static inline int cxListRemove( |
380 CxList *list, |
565 CxList *list, |
381 size_t index |
566 size_t index |
382 ) { |
567 ) { |
383 return list->cl->remove(list, index); |
568 return list->cl->remove(list, index, 1, NULL) == 0; |
|
569 } |
|
570 |
|
571 /** |
|
572 * Removes and returns the element at the specified index. |
|
573 * |
|
574 * No destructor is called and instead the element is copied to the |
|
575 * @p targetbuf which MUST be large enough to hold the removed element. |
|
576 * |
|
577 * @param list the list |
|
578 * @param index the index of the element |
|
579 * @param targetbuf a buffer where to copy the element |
|
580 * @retval zero success |
|
581 * @retval non-zero index out of bounds |
|
582 */ |
|
583 cx_attr_nonnull |
|
584 cx_attr_access_w(3) |
|
585 static inline int cxListRemoveAndGet( |
|
586 CxList *list, |
|
587 size_t index, |
|
588 void *targetbuf |
|
589 ) { |
|
590 return list->cl->remove(list, index, 1, targetbuf) == 0; |
|
591 } |
|
592 |
|
593 /** |
|
594 * Removes multiple element starting at the specified index. |
|
595 * |
|
596 * If an element destructor function is specified, it is called for each |
|
597 * element. It is guaranteed that the destructor is called before removing |
|
598 * the element, however, due to possible optimizations it is neither guaranteed |
|
599 * that the destructors are invoked for all elements before starting to remove |
|
600 * them, nor that the element is removed immediately after the destructor call |
|
601 * before proceeding to the next element. |
|
602 * |
|
603 * @param list the list |
|
604 * @param index the index of the element |
|
605 * @param num the number of elements to remove |
|
606 * @return the actual number of removed elements |
|
607 */ |
|
608 cx_attr_nonnull |
|
609 static inline size_t cxListRemoveArray( |
|
610 CxList *list, |
|
611 size_t index, |
|
612 size_t num |
|
613 ) { |
|
614 return list->cl->remove(list, index, num, NULL); |
|
615 } |
|
616 |
|
617 /** |
|
618 * Removes and returns multiple element starting at the specified index. |
|
619 * |
|
620 * No destructor is called and instead the elements are copied to the |
|
621 * @p targetbuf which MUST be large enough to hold all removed elements. |
|
622 * |
|
623 * @param list the list |
|
624 * @param index the index of the element |
|
625 * @param num the number of elements to remove |
|
626 * @param targetbuf a buffer where to copy the elements |
|
627 * @return the actual number of removed elements |
|
628 */ |
|
629 cx_attr_nonnull |
|
630 cx_attr_access_w(4) |
|
631 static inline size_t cxListRemoveArrayAndGet( |
|
632 CxList *list, |
|
633 size_t index, |
|
634 size_t num, |
|
635 void *targetbuf |
|
636 ) { |
|
637 return list->cl->remove(list, index, num, targetbuf); |
384 } |
638 } |
385 |
639 |
386 /** |
640 /** |
387 * Removes all elements from this list. |
641 * Removes all elements from this list. |
388 * |
642 * |
389 * If an element destructor function is specified, it is called for each |
643 * If element destructor functions are specified, they are called for each |
390 * element before removing them. |
644 * element before removing them. |
391 * |
645 * |
392 * @param list the list |
646 * @param list the list |
393 */ |
647 */ |
394 __attribute__((__nonnull__)) |
648 cx_attr_nonnull |
395 static inline void cxListClear(CxList *list) { |
649 static inline void cxListClear(CxList *list) { |
|
650 list->collection.sorted = true; // empty lists are always sorted |
396 list->cl->clear(list); |
651 list->cl->clear(list); |
397 } |
652 } |
398 |
653 |
399 /** |
654 /** |
400 * Swaps two items in the list. |
655 * Swaps two items in the list. |