src/cx/list.h

changeset 1101
2872f287fadc
parent 993
b642eca4b956
child 1109
89ec23988b88
equal deleted inserted replaced
1100:2ca6fa71e55e 1101:2872f287fadc
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 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 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE. 26 * POSSIBILITY OF SUCH DAMAGE.
27 */ 27 */
28 /** 28 /**
29 * \file list.h 29 * @file list.h
30 * \brief Interface for list implementations. 30 * @brief Interface for list implementations.
31 * \author Mike Becker 31 * @author Mike Becker
32 * \author Olaf Wintermann 32 * @author Olaf Wintermann
33 * \copyright 2-Clause BSD License 33 * @copyright 2-Clause BSD License
34 */ 34 */
35 35
36 #ifndef UCX_LIST_H 36 #ifndef UCX_LIST_H
37 #define UCX_LIST_H 37 #define UCX_LIST_H
38 38
74 * Destructor function. 74 * Destructor function.
75 * 75 *
76 * Implementations SHALL invoke the content destructor functions if provided 76 * Implementations SHALL invoke the content destructor functions if provided
77 * and SHALL deallocate the entire list memory. 77 * and SHALL deallocate the entire list memory.
78 */ 78 */
79 cx_attr_nonnull
80 void (*deallocate)(struct cx_list_s *list); 79 void (*deallocate)(struct cx_list_s *list);
81 80
82 /** 81 /**
83 * Member function for inserting a single element. 82 * Member function for inserting a single element.
84 * Implementors SHOULD see to performant implementations for corner cases. 83 * Implementors SHOULD see to performant implementations for corner cases.
85 */ 84 */
86 cx_attr_nonnull
87 int (*insert_element)( 85 int (*insert_element)(
88 struct cx_list_s *list, 86 struct cx_list_s *list,
89 size_t index, 87 size_t index,
90 const void *data 88 const void *data
91 ); 89 );
92 90
93 /** 91 /**
94 * Member function for inserting multiple elements. 92 * Member function for inserting multiple elements.
95 * Implementors SHOULD see to performant implementations for corner cases. 93 * Implementors SHOULD see to performant implementations for corner cases.
94 *
96 * @see cx_list_default_insert_array() 95 * @see cx_list_default_insert_array()
97 */ 96 */
98 cx_attr_nonnull
99 size_t (*insert_array)( 97 size_t (*insert_array)(
100 struct cx_list_s *list, 98 struct cx_list_s *list,
101 size_t index, 99 size_t index,
102 const void *data, 100 const void *data,
103 size_t n 101 size_t n
106 /** 104 /**
107 * Member function for inserting sorted elements into a sorted list. 105 * Member function for inserting sorted elements into a sorted list.
108 * 106 *
109 * @see cx_list_default_insert_sorted() 107 * @see cx_list_default_insert_sorted()
110 */ 108 */
111 cx_attr_nonnull
112 size_t (*insert_sorted)( 109 size_t (*insert_sorted)(
113 struct cx_list_s *list, 110 struct cx_list_s *list,
114 const void *sorted_data, 111 const void *sorted_data,
115 size_t n 112 size_t n
116 ); 113 );
117 114
118 /** 115 /**
119 * Member function for inserting an element relative to an iterator position. 116 * Member function for inserting an element relative to an iterator position.
120 */ 117 */
121 cx_attr_nonnull
122 int (*insert_iter)( 118 int (*insert_iter)(
123 struct cx_iterator_s *iter, 119 struct cx_iterator_s *iter,
124 const void *elem, 120 const void *elem,
125 int prepend 121 int prepend
126 ); 122 );
127 123
128 /** 124 /**
129 * Member function for removing elements. 125 * Member function for removing elements.
130 * 126 *
131 * Implementations SHALL check if \p targetbuf is set and copy the elements 127 * Implementations SHALL check if @p targetbuf is set and copy the elements
132 * to the buffer without invoking any destructor. 128 * to the buffer without invoking any destructor.
133 * When \p targetbuf is not set, the destructors SHALL be invoked. 129 * When @p targetbuf is not set, the destructors SHALL be invoked.
134 * 130 *
135 * The function SHALL return the actual number of elements removed, which 131 * The function SHALL return the actual number of elements removed, which
136 * might be lower than \p num when going out of bounds. 132 * might be lower than @p num when going out of bounds.
137 */ 133 */
138 cx_attr_nonnull_arg(1)
139 cx_attr_access_w(4)
140 size_t (*remove)( 134 size_t (*remove)(
141 struct cx_list_s *list, 135 struct cx_list_s *list,
142 size_t index, 136 size_t index,
143 size_t num, 137 size_t num,
144 void *targetbuf 138 void *targetbuf
145 ); 139 );
146 140
147 /** 141 /**
148 * Member function for removing all elements. 142 * Member function for removing all elements.
149 */ 143 */
150 cx_attr_nonnull
151 void (*clear)(struct cx_list_s *list); 144 void (*clear)(struct cx_list_s *list);
152 145
153 /** 146 /**
154 * Member function for swapping two elements. 147 * Member function for swapping two elements.
148 *
155 * @see cx_list_default_swap() 149 * @see cx_list_default_swap()
156 */ 150 */
157 cx_attr_nonnull
158 int (*swap)( 151 int (*swap)(
159 struct cx_list_s *list, 152 struct cx_list_s *list,
160 size_t i, 153 size_t i,
161 size_t j 154 size_t j
162 ); 155 );
163 156
164 /** 157 /**
165 * Member function for element lookup. 158 * Member function for element lookup.
166 */ 159 */
167 cx_attr_nonnull
168 cx_attr_nodiscard
169 void *(*at)( 160 void *(*at)(
170 const struct cx_list_s *list, 161 const struct cx_list_s *list,
171 size_t index 162 size_t index
172 ); 163 );
173 164
174 /** 165 /**
175 * Member function for finding and optionally removing an element. 166 * Member function for finding and optionally removing an element.
176 */ 167 */
177 cx_attr_nonnull
178 cx_attr_nodiscard
179 ssize_t (*find_remove)( 168 ssize_t (*find_remove)(
180 struct cx_list_s *list, 169 struct cx_list_s *list,
181 const void *elem, 170 const void *elem,
182 bool remove 171 bool remove
183 ); 172 );
184 173
185 /** 174 /**
186 * Member function for sorting the list in-place. 175 * Member function for sorting the list.
176 *
187 * @see cx_list_default_sort() 177 * @see cx_list_default_sort()
188 */ 178 */
189 cx_attr_nonnull
190 void (*sort)(struct cx_list_s *list); 179 void (*sort)(struct cx_list_s *list);
191 180
192 /** 181 /**
193 * Optional member function for comparing this list 182 * Optional member function for comparing this list
194 * to another list of the same type. 183 * to another list of the same type.
195 * If set to \c NULL, comparison won't be optimized. 184 * If set to @c NULL, comparison won't be optimized.
196 */ 185 */
197 cx_attr_nonnull 186 cx_attr_nonnull
198 int (*compare)( 187 int (*compare)(
199 const struct cx_list_s *list, 188 const struct cx_list_s *list,
200 const struct cx_list_s *other 189 const struct cx_list_s *other
201 ); 190 );
202 191
203 /** 192 /**
204 * Member function for reversing the order of the items. 193 * Member function for reversing the order of the items.
205 */ 194 */
206 cx_attr_nonnull
207 void (*reverse)(struct cx_list_s *list); 195 void (*reverse)(struct cx_list_s *list);
208 196
209 /** 197 /**
210 * Member function for returning an iterator pointing to the specified index. 198 * Member function for returning an iterator pointing to the specified index.
211 */ 199 */
212 cx_attr_nonnull
213 struct cx_iterator_s (*iterator)( 200 struct cx_iterator_s (*iterator)(
214 const struct cx_list_s *list, 201 const struct cx_list_s *list,
215 size_t index, 202 size_t index,
216 bool backward 203 bool backward
217 ); 204 );
243 * Default implementation of a sorted insert. 230 * Default implementation of a sorted insert.
244 * 231 *
245 * This function uses the array insert function to insert consecutive groups 232 * This function uses the array insert function to insert consecutive groups
246 * of sorted data. 233 * of sorted data.
247 * 234 *
248 * The source data \em must already be sorted wrt. the list's compare function. 235 * The source data @em must already be sorted wrt. the list's compare function.
249 * 236 *
250 * Use this in your own list class if you do not want to implement an optimized 237 * Use this in your own list class if you do not want to implement an optimized
251 * version for your list. 238 * version for your list.
252 * 239 *
253 * @param list the list 240 * @param list the list
283 * version for your list. 270 * version for your list.
284 * 271 *
285 * @param list the list in which to swap 272 * @param list the list in which to swap
286 * @param i index of one element 273 * @param i index of one element
287 * @param j index of the other element 274 * @param j index of the other element
288 * @return zero on success, non-zero when indices are out of bounds or memory 275 * @retval zero success
276 * @retval non-zero when indices are out of bounds or memory
289 * allocation for the temporary buffer fails 277 * allocation for the temporary buffer fails
290 */ 278 */
291 cx_attr_nonnull 279 cx_attr_nonnull
292 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j); 280 int cx_list_default_swap(struct cx_list_s *list, size_t i, size_t j);
293 281
349 /** 337 /**
350 * Adds an item to the end of the list. 338 * Adds an item to the end of the list.
351 * 339 *
352 * @param list the list 340 * @param list the list
353 * @param elem a pointer to the element to add 341 * @param elem a pointer to the element to add
354 * @return zero on success, non-zero on memory allocation failure 342 * @retval zero success
343 * @retval non-zero memory allocation failure
355 * @see cxListAddArray() 344 * @see cxListAddArray()
356 */ 345 */
357 cx_attr_nonnull 346 cx_attr_nonnull
358 static inline int cxListAdd( 347 static inline int cxListAdd(
359 CxList *list, 348 CxList *list,
366 * Adds multiple items to the end of the list. 355 * Adds multiple items to the end of the list.
367 * 356 *
368 * This method is more efficient than invoking cxListAdd() multiple times. 357 * This method is more efficient than invoking cxListAdd() multiple times.
369 * 358 *
370 * If there is not enough memory to add all elements, the returned value is 359 * If there is not enough memory to add all elements, the returned value is
371 * less than \p n. 360 * less than @p n.
372 * 361 *
373 * If this list is storing pointers instead of objects \p array is expected to 362 * If this list is storing pointers instead of objects @p array is expected to
374 * be an array of pointers. 363 * be an array of pointers.
375 * 364 *
376 * @param list the list 365 * @param list the list
377 * @param array a pointer to the elements to add 366 * @param array a pointer to the elements to add
378 * @param n the number of elements to add 367 * @param n the number of elements to add
388 } 377 }
389 378
390 /** 379 /**
391 * Inserts an item at the specified index. 380 * Inserts an item at the specified index.
392 * 381 *
393 * If \p index equals the list \c size, this is effectively cxListAdd(). 382 * If @p index equals the list @c size, this is effectively cxListAdd().
394 * 383 *
395 * @param list the list 384 * @param list the list
396 * @param index the index the element shall have 385 * @param index the index the element shall have
397 * @param elem a pointer to the element to add 386 * @param elem a pointer to the element to add
398 * @return zero on success, non-zero on memory allocation failure 387 * @retval zero success
399 * or when the index is out of bounds 388 * @retval non-zero memory allocation failure or the index is out of bounds
400 * @see cxListInsertAfter() 389 * @see cxListInsertAfter()
401 * @see cxListInsertBefore() 390 * @see cxListInsertBefore()
402 */ 391 */
403 cx_attr_nonnull 392 cx_attr_nonnull
404 static inline int cxListInsert( 393 static inline int cxListInsert(
412 /** 401 /**
413 * Inserts an item into a sorted list. 402 * Inserts an item into a sorted list.
414 * 403 *
415 * @param list the list 404 * @param list the list
416 * @param elem a pointer to the element to add 405 * @param elem a pointer to the element to add
417 * @return zero on success, non-zero on memory allocation failure 406 * @retval zero success
407 * @retval non-zero memory allocation failure
418 */ 408 */
419 cx_attr_nonnull 409 cx_attr_nonnull
420 static inline int cxListInsertSorted( 410 static inline int cxListInsertSorted(
421 CxList *list, 411 CxList *list,
422 const void *elem 412 const void *elem
425 return list->cl->insert_sorted(list, data, 1) == 0; 415 return list->cl->insert_sorted(list, data, 1) == 0;
426 } 416 }
427 417
428 /** 418 /**
429 * Inserts multiple items to the list at the specified index. 419 * Inserts multiple items to the list at the specified index.
430 * If \p index equals the list size, this is effectively cxListAddArray(). 420 * If @p index equals the list size, this is effectively cxListAddArray().
431 * 421 *
432 * This method is usually more efficient than invoking cxListInsert() 422 * This method is usually more efficient than invoking cxListInsert()
433 * multiple times. 423 * multiple times.
434 * 424 *
435 * If there is not enough memory to add all elements, the returned value is 425 * If there is not enough memory to add all elements, the returned value is
436 * less than \p n. 426 * less than @p n.
437 * 427 *
438 * If this list is storing pointers instead of objects \p array is expected to 428 * If this list is storing pointers instead of objects @p array is expected to
439 * be an array of pointers. 429 * be an array of pointers.
440 * 430 *
441 * @param list the list 431 * @param list the list
442 * @param index the index where to add the elements 432 * @param index the index where to add the elements
443 * @param array a pointer to the elements to add 433 * @param array a pointer to the elements to add
459 * 449 *
460 * This method is usually more efficient than inserting each element separately, 450 * This method is usually more efficient than inserting each element separately,
461 * because consecutive chunks of sorted data are inserted in one pass. 451 * because consecutive chunks of sorted data are inserted in one pass.
462 * 452 *
463 * If there is not enough memory to add all elements, the returned value is 453 * If there is not enough memory to add all elements, the returned value is
464 * less than \p n. 454 * less than @p n.
465 * 455 *
466 * If this list is storing pointers instead of objects \p array is expected to 456 * If this list is storing pointers instead of objects @p array is expected to
467 * be an array of pointers. 457 * be an array of pointers.
468 * 458 *
469 * @param list the list 459 * @param list the list
470 * @param array a pointer to the elements to add 460 * @param array a pointer to the elements to add
471 * @param n the number of elements to add 461 * @param n the number of elements to add
484 * Inserts an element after the current location of the specified iterator. 474 * Inserts an element after the current location of the specified iterator.
485 * 475 *
486 * The used iterator remains operational, but all other active iterators should 476 * The used iterator remains operational, but all other active iterators should
487 * be considered invalidated. 477 * be considered invalidated.
488 * 478 *
489 * If \p iter is not a list iterator, the behavior is undefined. 479 * If @p iter is not a list iterator, the behavior is undefined.
490 * If \p iter is a past-the-end iterator, the new element gets appended to the list. 480 * If @p iter is a past-the-end iterator, the new element gets appended to the list.
491 * 481 *
492 * @param iter an iterator 482 * @param iter an iterator
493 * @param elem the element to insert 483 * @param elem the element to insert
494 * @return zero on success, non-zero on memory allocation failure 484 * @retval zero success
485 * @retval non-zero memory allocation failure
495 * @see cxListInsert() 486 * @see cxListInsert()
496 * @see cxListInsertBefore() 487 * @see cxListInsertBefore()
497 */ 488 */
498 cx_attr_nonnull 489 cx_attr_nonnull
499 static inline int cxListInsertAfter( 490 static inline int cxListInsertAfter(
507 * Inserts an element before the current location of the specified iterator. 498 * Inserts an element before the current location of the specified iterator.
508 * 499 *
509 * The used iterator remains operational, but all other active iterators should 500 * The used iterator remains operational, but all other active iterators should
510 * be considered invalidated. 501 * be considered invalidated.
511 * 502 *
512 * If \p iter is not a list iterator, the behavior is undefined. 503 * If @p iter is not a list iterator, the behavior is undefined.
513 * If \p iter is a past-the-end iterator, the new element gets appended to the list. 504 * If @p iter is a past-the-end iterator, the new element gets appended to the list.
514 * 505 *
515 * @param iter an iterator 506 * @param iter an iterator
516 * @param elem the element to insert 507 * @param elem the element to insert
517 * @return zero on success, non-zero on memory allocation failure 508 * @retval zero success
509 * @retval non-zero memory allocation failure
518 * @see cxListInsert() 510 * @see cxListInsert()
519 * @see cxListInsertAfter() 511 * @see cxListInsertAfter()
520 */ 512 */
521 cx_attr_nonnull 513 cx_attr_nonnull
522 static inline int cxListInsertBefore( 514 static inline int cxListInsertBefore(
532 * If an element destructor function is specified, it is called before 524 * If an element destructor function is specified, it is called before
533 * removing the element. 525 * removing the element.
534 * 526 *
535 * @param list the list 527 * @param list the list
536 * @param index the index of the element 528 * @param index the index of the element
537 * @return zero on success, non-zero if the index is out of bounds 529 * @retval zero success
530 * @retval non-zero index out of bounds
538 */ 531 */
539 cx_attr_nonnull 532 cx_attr_nonnull
540 static inline int cxListRemove( 533 static inline int cxListRemove(
541 CxList *list, 534 CxList *list,
542 size_t index 535 size_t index
546 539
547 /** 540 /**
548 * Removes and returns the element at the specified index. 541 * Removes and returns the element at the specified index.
549 * 542 *
550 * No destructor is called and instead the element is copied to the 543 * No destructor is called and instead the element is copied to the
551 * \p targetbuf which MUST be large enough to hold the removed element. 544 * @p targetbuf which MUST be large enough to hold the removed element.
552 * 545 *
553 * @param list the list 546 * @param list the list
554 * @param index the index of the element 547 * @param index the index of the element
555 * @param targetbuf a buffer where to copy the element 548 * @param targetbuf a buffer where to copy the element
556 * @return zero on success, non-zero if the index is out of bounds 549 * @retval zero success
550 * @retval non-zero index out of bounds
557 */ 551 */
558 cx_attr_nonnull 552 cx_attr_nonnull
559 cx_attr_access_w(3) 553 cx_attr_access_w(3)
560 static inline int cxListRemoveAndGet( 554 static inline int cxListRemoveAndGet(
561 CxList *list, 555 CxList *list,
591 585
592 /** 586 /**
593 * Removes and returns multiple element starting at the specified index. 587 * Removes and returns multiple element starting at the specified index.
594 * 588 *
595 * No destructor is called and instead the elements are copied to the 589 * No destructor is called and instead the elements are copied to the
596 * \p targetbuf which MUST be large enough to hold all removed elements. 590 * @p targetbuf which MUST be large enough to hold all removed elements.
597 * 591 *
598 * @param list the list 592 * @param list the list
599 * @param index the index of the element 593 * @param index the index of the element
600 * @param num the number of elements to remove 594 * @param num the number of elements to remove
601 * @param targetbuf a buffer where to copy the elements 595 * @param targetbuf a buffer where to copy the elements
613 } 607 }
614 608
615 /** 609 /**
616 * Removes all elements from this list. 610 * Removes all elements from this list.
617 * 611 *
618 * If an element destructor function is specified, it is called for each 612 * If element destructor functions are specified, they are called for each
619 * element before removing them. 613 * element before removing them.
620 * 614 *
621 * @param list the list 615 * @param list the list
622 */ 616 */
623 cx_attr_nonnull 617 cx_attr_nonnull
632 * it is necessary. 626 * it is necessary.
633 * 627 *
634 * @param list the list 628 * @param list the list
635 * @param i the index of the first element 629 * @param i the index of the first element
636 * @param j the index of the second element 630 * @param j the index of the second element
637 * @return zero on success, non-zero if one of the indices is out of bounds 631 * @retval zero success
632 * @retval non-zero one of the indices is out of bounds
633 * or the swap needed extra memory but allocation failed
638 */ 634 */
639 cx_attr_nonnull 635 cx_attr_nonnull
640 static inline int cxListSwap( 636 static inline int cxListSwap(
641 CxList *list, 637 CxList *list,
642 size_t i, 638 size_t i,
648 /** 644 /**
649 * Returns a pointer to the element at the specified index. 645 * Returns a pointer to the element at the specified index.
650 * 646 *
651 * @param list the list 647 * @param list the list
652 * @param index the index of the element 648 * @param index the index of the element
653 * @return a pointer to the element or \c NULL if the index is out of bounds 649 * @return a pointer to the element or @c NULL if the index is out of bounds
654 */ 650 */
655 cx_attr_nonnull 651 cx_attr_nonnull
656 static inline void *cxListAt( 652 static inline void *cxListAt(
657 const CxList *list, 653 const CxList *list,
658 size_t index 654 size_t index
801 static inline CxIterator cxListMutBackwardsIterator(CxList *list) { 797 static inline CxIterator cxListMutBackwardsIterator(CxList *list) {
802 return cxListMutBackwardsIteratorAt(list, list->collection.size - 1); 798 return cxListMutBackwardsIteratorAt(list, list->collection.size - 1);
803 } 799 }
804 800
805 /** 801 /**
806 * Returns the index of the first element that equals \p elem. 802 * Returns the index of the first element that equals @p elem.
807 * 803 *
808 * Determining equality is performed by the list's comparator function. 804 * Determining equality is performed by the list's comparator function.
809 * 805 *
810 * @param list the list 806 * @param list the list
811 * @param elem the element to find 807 * @param elem the element to find
820 ) { 816 ) {
821 return list->cl->find_remove((CxList*)list, elem, false); 817 return list->cl->find_remove((CxList*)list, elem, false);
822 } 818 }
823 819
824 /** 820 /**
825 * Removes and returns the index of the first element that equals \p elem. 821 * Removes and returns the index of the first element that equals @p elem.
826 * 822 *
827 * Determining equality is performed by the list's comparator function. 823 * Determining equality is performed by the list's comparator function.
828 * 824 *
829 * @param list the list 825 * @param list the list
830 * @param elem the element to find and remove 826 * @param elem the element to find and remove
838 ) { 834 ) {
839 return list->cl->find_remove(list, elem, true); 835 return list->cl->find_remove(list, elem, true);
840 } 836 }
841 837
842 /** 838 /**
843 * Sorts the list in-place. 839 * Sorts the list.
844 * 840 *
845 * \remark The underlying sort algorithm is implementation defined. 841 * @remark The underlying sort algorithm is implementation defined.
846 * 842 *
847 * @param list the list 843 * @param list the list
848 */ 844 */
849 cx_attr_nonnull 845 cx_attr_nonnull
850 static inline void cxListSort(CxList *list) { 846 static inline void cxListSort(CxList *list) {
867 * First, the list sizes are compared. 863 * First, the list sizes are compared.
868 * If they match, the lists are compared element-wise. 864 * If they match, the lists are compared element-wise.
869 * 865 *
870 * @param list the list 866 * @param list the list
871 * @param other the list to compare to 867 * @param other the list to compare to
872 * @return zero, if both lists are equal element wise, 868 * @retval zero both lists are equal element wise
873 * negative if the first list is smaller, positive if the first list is larger 869 * @retval negative the first list is smaller
870 * or the first non-equal element in the first list is smaller
871 * @retval positive the first list is larger
872 * or the first non-equal element in the first list is larger
874 */ 873 */
875 cx_attr_nonnull 874 cx_attr_nonnull
876 cx_attr_nodiscard 875 cx_attr_nodiscard
877 int cxListCompare( 876 int cxListCompare(
878 const CxList *list, 877 const CxList *list,
880 ); 879 );
881 880
882 /** 881 /**
883 * Deallocates the memory of the specified list structure. 882 * Deallocates the memory of the specified list structure.
884 * 883 *
885 * Also calls the content destructor function for each element, if specified. 884 * Also calls the content destructor functions for each element, if specified.
886 * 885 *
887 * @param list the list which shall be freed 886 * @param list the list which shall be freed
888 */ 887 */
889 static inline void cxListFree(CxList *list) { 888 static inline void cxListFree(CxList *list) {
890 if (list == NULL) return; 889 if (list == NULL) return;
893 892
894 /** 893 /**
895 * A shared instance of an empty list. 894 * A shared instance of an empty list.
896 * 895 *
897 * Writing to that list is not allowed. 896 * Writing to that list is not allowed.
897 *
898 * You can use this is a placeholder for initializing CxList pointers
899 * for which you do not want to reserve memory right from the beginning.
898 */ 900 */
899 extern CxList *const cxEmptyList; 901 extern CxList *const cxEmptyList;
900 902
901 903
902 #ifdef __cplusplus 904 #ifdef __cplusplus

mercurial