UNIXworkcode

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 801