ucx/cx/list.h

changeset 431
bb7da585debc
parent 324
ce13a778654a
child 440
7c4b9cba09ca
equal deleted inserted replaced
169:fe49cff3c571 431:bb7da585debc
1 /*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3 *
4 * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28 /**
29 * \file list.h
30 * \brief Interface for list implementations.
31 * \author Mike Becker
32 * \author Olaf Wintermann
33 * \copyright 2-Clause BSD License
34 */
35
36 #ifndef UCX_LIST_H
37 #define UCX_LIST_H
38
39 #include "common.h"
40 #include "collection.h"
41
42 #ifdef __cplusplus
43 extern "C" {
44 #endif
45
46 /**
47 * List class type.
48 */
49 typedef struct cx_list_class_s cx_list_class;
50
51 /**
52 * Structure for holding the base data of a list.
53 */
54 struct cx_list_s {
55 CX_COLLECTION_BASE;
56 /**
57 * The list class definition.
58 */
59 const cx_list_class *cl;
60 /**
61 * The actual implementation in case the list class is delegating.
62 */
63 const cx_list_class *climpl;
64 };
65
66 /**
67 * The class definition for arbitrary lists.
68 */
69 struct cx_list_class_s {
70 /**
71 * Destructor function.
72 *
73 * Implementations SHALL invoke the content destructor functions if provided
74 * and SHALL deallocate the list memory.
75 */
76 void (*destructor)(struct cx_list_s *list);
77
78 /**
79 * Member function for inserting a single element.
80 * Implementors SHOULD see to performant implementations for corner cases.
81 */
82 int (*insert_element)(
83 struct cx_list_s *list,
84 size_t index,
85 const void *data
86 );
87
88 /**
89 * Member function for inserting multiple elements.
90 * Implementors SHOULD see to performant implementations for corner cases.
91 * @see cx_list_default_insert_array()
92 */
93 size_t (*insert_array)(
94 struct cx_list_s *list,
95 size_t index,
96 const void *data,
97 size_t n
98 );
99
100 /**
101 * Member function for inserting sorted elements into a sorted list.
102 *
103 * @see cx_list_default_insert_sorted()
104 */
105 size_t (*insert_sorted)(
106 struct cx_list_s *list,
107 const void *sorted_data,
108 size_t n
109 );
110
111 /**
112 * Member function for inserting an element relative to an iterator position.
113 */
114 int (*insert_iter)(
115 struct cx_iterator_s *iter,
116 const void *elem,
117 int prepend
118 );
119
120 /**
121 * Member function for removing an element.
122 */
123 int (*remove)(
124 struct cx_list_s *list,
125 size_t index
126 );
127
128 /**
129 * Member function for removing all elements.
130 */
131 void (*clear)(struct cx_list_s *list);
132
133 /**
134 * Member function for swapping two elements.
135 * @see cx_list_default_swap()
136 */
137 int (*swap)(
138 struct cx_list_s *list,
139 size_t i,
140 size_t j
141 );
142
143 /**
144 * Member function for element lookup.
145 */
146 void *(*at)(
147 const struct cx_list_s *list,
148 size_t index
149 );
150
151 /**
152 * Member function for finding and optionally removing an element.
153 */
154 ssize_t (*find_remove)(
155 struct cx_list_s *list,
156 const void *elem,
157 bool remove
158 );
159
160 /**
161 * Member function for sorting the list in-place.
162 * @see cx_list_default_sort()
163 */
164 void (*sort)(struct cx_list_s *list);
165
166 /**
167 * Optional member function for comparing this list
168 * to another list of the same type.
169 * If set to \c NULL, comparison won't be optimized.
170 */
171 int (*compare)(
172 const struct cx_list_s *list,
173 const struct cx_list_s *other
174 );
175
176 /**
177 * Member function for reversing the order of the items.
178 */
179 void (*reverse)(struct cx_list_s *list);
180
181 /**
182 * Member function for returning an iterator pointing to the specified index.
183 */
184 struct cx_iterator_s (*iterator)(
185 const struct cx_list_s *list,
186 size_t index,
187 bool backward
188 );
189 };
190
191 /**
192 * Default implementation of an array insert.
193 *
194 * This function uses the element insert function for each element of the array.
195 *
196 * Use this in your own list class if you do not want to implement an optimized
197 * version for your list.
198 *
199 * @param list the list
200 * @param index the index where to insert the data
201 * @param data a pointer to the array of data to insert
202 * @param n the number of elements to insert
203 * @return the number of elements actually inserted
204 */
205 __attribute__((__nonnull__))
206 size_t cx_list_default_insert_array(
207 struct cx_list_s *list,
208 size_t index,
209 const void *data,
210 size_t n
211 );
212
213 /**
214 * Default implementation of a sorted insert.
215 *
216 * This function uses the array insert function to insert consecutive groups
217 * of sorted data.
218 *
219 * The source data \em must already be sorted wrt. the list's compare function.
220 *
221 * Use this in your own list class if you do not want to implement an optimized
222 * version for your list.
223 *
224 * @param list the list
225 * @param sorted_data a pointer to the array of pre-sorted data to insert
226 * @param n the number of elements to insert
227 * @return the number of elements actually inserted
228 */
229 __attribute__((__nonnull__))
230 size_t cx_list_default_insert_sorted(
231 struct cx_list_s *list,
232 const void *sorted_data,
233 size_t n
234 );
235
236 /**
237 * Default unoptimized sort implementation.
238 *
239 * This function will copy all data to an array, sort the array with standard
240 * qsort, and then copy the data back to the list memory.
241 *
242 * Use this in your own list class if you do not want to implement an optimized
243 * version for your list.
244 *
245 * @param list the list that shall be sorted
246 */
247 __attribute__((__nonnull__))
248 void cx_list_default_sort(struct cx_list_s *list);
249
250 /**
251 * Default unoptimized swap implementation.
252 *
253 * Use this in your own list class if you do not want to implement an optimized
254 * version for your list.
255 *
256 * @param list the list in which to swap
257 * @param i index of one element
258 * @param j index of the other element
259 * @return zero on success, non-zero when indices are out of bounds or memory
260 * allocation for the temporary buffer fails
261 */
262 __attribute__((__nonnull__))
263 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
264
265 /**
266 * Common type for all list implementations.
267 */
268 typedef struct cx_list_s CxList;
269
270 /**
271 * Advises the list to store copies of the objects (default mode of operation).
272 *
273 * Retrieving objects from this list will yield pointers to the copies stored
274 * within this list.
275 *
276 * @param list the list
277 * @see cxListStorePointers()
278 */
279 __attribute__((__nonnull__))
280 void cxListStoreObjects(CxList *list);
281
282 /**
283 * Advises the list to only store pointers to the objects.
284 *
285 * Retrieving objects from this list will yield the original pointers stored.
286 *
287 * @note This function forcibly sets the element size to the size of a pointer.
288 * Invoking this function on a non-empty list that already stores copies of
289 * objects is undefined.
290 *
291 * @param list the list
292 * @see cxListStoreObjects()
293 */
294 __attribute__((__nonnull__))
295 void cxListStorePointers(CxList *list);
296
297 /**
298 * Returns true, if this list is storing pointers instead of the actual data.
299 *
300 * @param list
301 * @return true, if this list is storing pointers
302 * @see cxListStorePointers()
303 */
304 __attribute__((__nonnull__))
305 static inline bool cxListIsStoringPointers(const CxList *list) {
306 return list->collection.store_pointer;
307 }
308
309 /**
310 * Returns the number of elements currently stored in the list.
311 *
312 * @param list the list
313 * @return the number of currently stored elements
314 */
315 __attribute__((__nonnull__))
316 static inline size_t cxListSize(const CxList *list) {
317 return list->collection.size;
318 }
319
320 /**
321 * Adds an item to the end of the list.
322 *
323 * @param list the list
324 * @param elem a pointer to the element to add
325 * @return zero on success, non-zero on memory allocation failure
326 * @see cxListAddArray()
327 */
328 __attribute__((__nonnull__))
329 static inline int cxListAdd(
330 CxList *list,
331 const void *elem
332 ) {
333 return list->cl->insert_element(list, list->collection.size, elem);
334 }
335
336 /**
337 * Adds multiple items to the end of the list.
338 *
339 * This method is more efficient than invoking cxListAdd() multiple times.
340 *
341 * If there is not enough memory to add all elements, the returned value is
342 * less than \p n.
343 *
344 * If this list is storing pointers instead of objects \p array is expected to
345 * be an array of pointers.
346 *
347 * @param list the list
348 * @param array a pointer to the elements to add
349 * @param n the number of elements to add
350 * @return the number of added elements
351 */
352 __attribute__((__nonnull__))
353 static inline size_t cxListAddArray(
354 CxList *list,
355 const void *array,
356 size_t n
357 ) {
358 return list->cl->insert_array(list, list->collection.size, array, n);
359 }
360
361 /**
362 * Inserts an item at the specified index.
363 *
364 * If \p index equals the list \c size, this is effectively cxListAdd().
365 *
366 * @param list the list
367 * @param index the index the element shall have
368 * @param elem a pointer to the element to add
369 * @return zero on success, non-zero on memory allocation failure
370 * or when the index is out of bounds
371 * @see cxListInsertAfter()
372 * @see cxListInsertBefore()
373 */
374 __attribute__((__nonnull__))
375 static inline int cxListInsert(
376 CxList *list,
377 size_t index,
378 const void *elem
379 ) {
380 return list->cl->insert_element(list, index, elem);
381 }
382
383 /**
384 * Inserts an item into a sorted list.
385 *
386 * @param list the list
387 * @param elem a pointer to the element to add
388 * @return zero on success, non-zero on memory allocation failure
389 */
390 __attribute__((__nonnull__))
391 static inline int cxListInsertSorted(
392 CxList *list,
393 const void *elem
394 ) {
395 const void *data = list->collection.store_pointer ? &elem : elem;
396 return list->cl->insert_sorted(list, data, 1) == 0;
397 }
398
399 /**
400 * Inserts multiple items to the list at the specified index.
401 * If \p index equals the list size, this is effectively cxListAddArray().
402 *
403 * This method is usually more efficient than invoking cxListInsert()
404 * multiple times.
405 *
406 * If there is not enough memory to add all elements, the returned value is
407 * less than \p n.
408 *
409 * If this list is storing pointers instead of objects \p array is expected to
410 * be an array of pointers.
411 *
412 * @param list the list
413 * @param index the index where to add the elements
414 * @param array a pointer to the elements to add
415 * @param n the number of elements to add
416 * @return the number of added elements
417 */
418 __attribute__((__nonnull__))
419 static inline size_t cxListInsertArray(
420 CxList *list,
421 size_t index,
422 const void *array,
423 size_t n
424 ) {
425 return list->cl->insert_array(list, index, array, n);
426 }
427
428 /**
429 * Inserts a sorted array into a sorted list.
430 *
431 * This method is usually more efficient than inserting each element separately,
432 * because consecutive chunks of sorted data are inserted in one pass.
433 *
434 * If there is not enough memory to add all elements, the returned value is
435 * less than \p n.
436 *
437 * If this list is storing pointers instead of objects \p array is expected to
438 * be an array of pointers.
439 *
440 * @param list the list
441 * @param array a pointer to the elements to add
442 * @param n the number of elements to add
443 * @return the number of added elements
444 */
445 __attribute__((__nonnull__))
446 static inline size_t cxListInsertSortedArray(
447 CxList *list,
448 const void *array,
449 size_t n
450 ) {
451 return list->cl->insert_sorted(list, array, n);
452 }
453
454 /**
455 * Inserts an element after the current location of the specified iterator.
456 *
457 * The used iterator remains operational, but all other active iterators should
458 * be considered invalidated.
459 *
460 * If \p iter is not a list iterator, the behavior is undefined.
461 * If \p iter is a past-the-end iterator, the new element gets appended to the list.
462 *
463 * @param iter an iterator
464 * @param elem the element to insert
465 * @return zero on success, non-zero on memory allocation failure
466 * @see cxListInsert()
467 * @see cxListInsertBefore()
468 */
469 __attribute__((__nonnull__))
470 static inline int cxListInsertAfter(
471 CxIterator *iter,
472 const void *elem
473 ) {
474 return ((struct cx_list_s *) iter->src_handle.m)->cl->insert_iter(iter, elem, 0);
475 }
476
477 /**
478 * Inserts an element before the current location of the specified iterator.
479 *
480 * The used iterator remains operational, but all other active iterators should
481 * be considered invalidated.
482 *
483 * If \p iter is not a list iterator, the behavior is undefined.
484 * If \p iter is a past-the-end iterator, the new element gets appended to the list.
485 *
486 * @param iter an iterator
487 * @param elem the element to insert
488 * @return zero on success, non-zero on memory allocation failure
489 * @see cxListInsert()
490 * @see cxListInsertAfter()
491 */
492 __attribute__((__nonnull__))
493 static inline int cxListInsertBefore(
494 CxIterator *iter,
495 const void *elem
496 ) {
497 return ((struct cx_list_s *) iter->src_handle.m)->cl->insert_iter(iter, elem, 1);
498 }
499
500 /**
501 * Removes the element at the specified index.
502 *
503 * If an element destructor function is specified, it is called before
504 * removing the element.
505 *
506 * @param list the list
507 * @param index the index of the element
508 * @return zero on success, non-zero if the index is out of bounds
509 */
510 __attribute__((__nonnull__))
511 static inline int cxListRemove(
512 CxList *list,
513 size_t index
514 ) {
515 return list->cl->remove(list, index);
516 }
517
518 /**
519 * Removes all elements from this list.
520 *
521 * If an element destructor function is specified, it is called for each
522 * element before removing them.
523 *
524 * @param list the list
525 */
526 __attribute__((__nonnull__))
527 static inline void cxListClear(CxList *list) {
528 list->cl->clear(list);
529 }
530
531 /**
532 * Swaps two items in the list.
533 *
534 * Implementations should only allocate temporary memory for the swap, if
535 * it is necessary.
536 *
537 * @param list the list
538 * @param i the index of the first element
539 * @param j the index of the second element
540 * @return zero on success, non-zero if one of the indices is out of bounds
541 */
542 __attribute__((__nonnull__))
543 static inline int cxListSwap(
544 CxList *list,
545 size_t i,
546 size_t j
547 ) {
548 return list->cl->swap(list, i, j);
549 }
550
551 /**
552 * Returns a pointer to the element at the specified index.
553 *
554 * @param list the list
555 * @param index the index of the element
556 * @return a pointer to the element or \c NULL if the index is out of bounds
557 */
558 __attribute__((__nonnull__))
559 static inline void *cxListAt(
560 CxList *list,
561 size_t index
562 ) {
563 return list->cl->at(list, index);
564 }
565
566 /**
567 * Returns an iterator pointing to the item at the specified index.
568 *
569 * The returned iterator is position-aware.
570 *
571 * If the index is out of range, a past-the-end iterator will be returned.
572 *
573 * @param list the list
574 * @param index the index where the iterator shall point at
575 * @return a new iterator
576 */
577 __attribute__((__nonnull__, __warn_unused_result__))
578 static inline CxIterator cxListIteratorAt(
579 const CxList *list,
580 size_t index
581 ) {
582 return list->cl->iterator(list, index, false);
583 }
584
585 /**
586 * Returns a backwards iterator pointing to the item at the specified index.
587 *
588 * The returned iterator is position-aware.
589 *
590 * If the index is out of range, a past-the-end iterator will be returned.
591 *
592 * @param list the list
593 * @param index the index where the iterator shall point at
594 * @return a new iterator
595 */
596 __attribute__((__nonnull__, __warn_unused_result__))
597 static inline CxIterator cxListBackwardsIteratorAt(
598 const CxList *list,
599 size_t index
600 ) {
601 return list->cl->iterator(list, index, true);
602 }
603
604 /**
605 * Returns a mutating iterator pointing to the item at the specified index.
606 *
607 * The returned iterator is position-aware.
608 *
609 * If the index is out of range, a past-the-end iterator will be returned.
610 *
611 * @param list the list
612 * @param index the index where the iterator shall point at
613 * @return a new iterator
614 */
615 __attribute__((__nonnull__, __warn_unused_result__))
616 CxIterator cxListMutIteratorAt(
617 CxList *list,
618 size_t index
619 );
620
621 /**
622 * Returns a mutating backwards iterator pointing to the item at the
623 * specified index.
624 *
625 * The returned iterator is position-aware.
626 *
627 * If the index is out of range, a past-the-end iterator will be returned.
628 *
629 * @param list the list
630 * @param index the index where the iterator shall point at
631 * @return a new iterator
632 */
633 __attribute__((__nonnull__, __warn_unused_result__))
634 CxIterator cxListMutBackwardsIteratorAt(
635 CxList *list,
636 size_t index
637 );
638
639 /**
640 * Returns an iterator pointing to the first item of the list.
641 *
642 * The returned iterator is position-aware.
643 *
644 * If the list is empty, a past-the-end iterator will be returned.
645 *
646 * @param list the list
647 * @return a new iterator
648 */
649 __attribute__((__nonnull__, __warn_unused_result__))
650 static inline CxIterator cxListIterator(const CxList *list) {
651 return list->cl->iterator(list, 0, false);
652 }
653
654 /**
655 * Returns a mutating iterator pointing to the first item of the list.
656 *
657 * The returned iterator is position-aware.
658 *
659 * If the list is empty, a past-the-end iterator will be returned.
660 *
661 * @param list the list
662 * @return a new iterator
663 */
664 __attribute__((__nonnull__, __warn_unused_result__))
665 static inline CxIterator cxListMutIterator(CxList *list) {
666 return cxListMutIteratorAt(list, 0);
667 }
668
669
670 /**
671 * Returns a backwards iterator pointing to the last item of the list.
672 *
673 * The returned iterator is position-aware.
674 *
675 * If the list is empty, a past-the-end iterator will be returned.
676 *
677 * @param list the list
678 * @return a new iterator
679 */
680 __attribute__((__nonnull__, __warn_unused_result__))
681 static inline CxIterator cxListBackwardsIterator(const CxList *list) {
682 return list->cl->iterator(list, list->collection.size - 1, true);
683 }
684
685 /**
686 * Returns a mutating backwards iterator pointing to the last item of the list.
687 *
688 * The returned iterator is position-aware.
689 *
690 * If the list is empty, a past-the-end iterator will be returned.
691 *
692 * @param list the list
693 * @return a new iterator
694 */
695 __attribute__((__nonnull__, __warn_unused_result__))
696 static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
697 return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
698 }
699
700 /**
701 * Returns the index of the first element that equals \p elem.
702 *
703 * Determining equality is performed by the list's comparator function.
704 *
705 * @param list the list
706 * @param elem the element to find
707 * @return the index of the element or a negative
708 * value when the element is not found
709 */
710 __attribute__((__nonnull__))
711 static inline ssize_t cxListFind(
712 const CxList *list,
713 const void *elem
714 ) {
715 return list->cl->find_remove((CxList*)list, elem, false);
716 }
717
718 /**
719 * Removes and returns the index of the first element that equals \p elem.
720 *
721 * Determining equality is performed by the list's comparator function.
722 *
723 * @param list the list
724 * @param elem the element to find and remove
725 * @return the index of the now removed element or a negative
726 * value when the element is not found or could not be removed
727 */
728 __attribute__((__nonnull__))
729 static inline ssize_t cxListFindRemove(
730 CxList *list,
731 const void *elem
732 ) {
733 return list->cl->find_remove(list, elem, true);
734 }
735
736 /**
737 * Sorts the list in-place.
738 *
739 * \remark The underlying sort algorithm is implementation defined.
740 *
741 * @param list the list
742 */
743 __attribute__((__nonnull__))
744 static inline void cxListSort(CxList *list) {
745 list->cl->sort(list);
746 }
747
748 /**
749 * Reverses the order of the items.
750 *
751 * @param list the list
752 */
753 __attribute__((__nonnull__))
754 static inline void cxListReverse(CxList *list) {
755 list->cl->reverse(list);
756 }
757
758 /**
759 * Compares a list to another list of the same type.
760 *
761 * First, the list sizes are compared.
762 * If they match, the lists are compared element-wise.
763 *
764 * @param list the list
765 * @param other the list to compare to
766 * @return zero, if both lists are equal element wise,
767 * negative if the first list is smaller, positive if the first list is larger
768 */
769 __attribute__((__nonnull__))
770 int cxListCompare(
771 const CxList *list,
772 const CxList *other
773 );
774
775 /**
776 * Deallocates the memory of the specified list structure.
777 *
778 * Also calls content a destructor function, depending on the configuration
779 * in CxList.content_destructor_type.
780 *
781 * This function itself is a destructor function for the CxList.
782 *
783 * @param list the list which shall be destroyed
784 */
785 __attribute__((__nonnull__))
786 void cxListDestroy(CxList *list);
787
788 /**
789 * A shared instance of an empty list.
790 *
791 * Writing to that list is undefined.
792 */
793 extern CxList * const cxEmptyList;
794
795
796 #ifdef __cplusplus
797 } // extern "C"
798 #endif
799
800 #endif // UCX_LIST_H

mercurial