00001 /* 00002 00003 The BLAH library, a container library 00004 Copyright (C) 1997-2004 The CDG Team <cdg@nats.informatik.uni-hamburg.de> 00005 00006 This program is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 2 of the License, or 00009 (at your option) any later version. 00010 00011 This program is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program; if not, write to the Free Software 00018 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00019 00020 Contact: blah@nats.informatik.uni-hamburg.de 00021 00022 $Id: list.c,v 1.22 2004/05/14 09:25:54 foth Exp $ 00023 00024 */ 00025 00026 /* ---------------------------------------------------------------------- 00027 * @defgroup List Lists 00028 * A list container. A list is a sequence of data objects where the data items are usually 00029 * access from the beginning of list. The head of a list is the first 00030 * data item and the tail is a list containing the remaining objects. 00031 * @{ 00032 */ 00033 00034 /* ----INCLUDES------------------------------------------------------- */ 00035 #include <stdio.h> 00036 #include <stdarg.h> 00037 #include "blah.h" 00038 00039 /* ---------------------------------------------------------------------- 00040 * a list node. 00041 */ 00042 struct ListStruct { 00043 Pointer item; /**< void element link to member of list */ 00044 struct ListStruct *next; /**< link to the next element in the list */ 00045 }; 00046 00047 /* ---------------------------------------------------------------------- 00048 * this is used to debug the cell allocation for Lists. 00049 * 00050 * It expands to _newCell when BLAH is compiled with -DLIST_DEBUG or to the normal 00051 * memMalloc function. 00052 * 00053 * @see _newCell, freeListCell 00054 */ 00055 #ifdef LIST_DEBUG 00056 #define newListCell _newCell() 00057 00058 /** @see newListCell */ 00059 List _newCell(void) { 00060 List result = memMalloc(sizeof(ListStruct)); 00061 printf("+ cell %p\n", result); 00062 return result; 00063 } 00064 00065 #else 00066 #define newListCell (List)memMalloc(sizeof(ListStruct)) 00067 #endif 00068 00069 /* ---------------------------------------------------------------------- 00070 * this is used to debug the cell deallocation for Lists. 00071 * It expands to _freeCell when BLAH is compiled with -DLIST_DEBUG or to the normal 00072 * memFree function. 00073 * 00074 * @see newCell 00075 */ 00076 #ifdef LIST_DEBUG 00077 #define freeListCell(x) _freeCell(x) 00078 00079 /** @see freeListCell */ 00080 void _freeCell(List cell) { 00081 printf("- cell %p\n",cell); 00082 memFree(cell); 00083 } 00084 00085 #else 00086 #define freeListCell memFree 00087 #endif 00088 00089 /* ---------------------------------------------------------------------- */ 00090 00091 /* ---------------------------------------------------------------------- 00092 * get a new list. 00093 * 00094 * A new List is represented by NULL. 00095 * 00096 * @returns NULL 00097 */ 00098 List listNew() 00099 { 00100 return NULL; 00101 } 00102 00103 /* ---------------------------------------------------------------------- 00104 * returns first item in list. 00105 * 00106 * @param l the list whose first item has to be returned. 00107 * @returns the first item in the list l. 00108 */ 00109 Pointer listElement(List l) 00110 { 00111 return l->item; 00112 } 00113 00114 /* ---------------------------------------------------------------------- 00115 * returns the tail of the list. 00116 * 00117 * @param l the list whose tail has to be returned. 00118 * @returns the last item of the list. 00119 */ 00120 List listNext(List l) 00121 { 00122 return l->next; 00123 } 00124 00125 /* ---------------------------------------------------------------------- 00126 * set the item of the current list cell. 00127 * 00128 * @param l the list from which the specified item has to be set. 00129 * @param value the value of the item in the list that has to be set. 00130 * @returns the list after setting the specified item. 00131 */ 00132 Pointer listSetElement(List l, Pointer value) 00133 { 00134 l->item = value; 00135 return value; 00136 } 00137 00138 /* ---------------------------------------------------------------------- 00139 * set the next of the current list cell. 00140 * 00141 * @param l the list from which the specified item has to be set. 00142 * @param m next of the current list cell 00143 */ 00144 Pointer listSetNext(List l, List m) 00145 { 00146 l->next = m; 00147 return m; 00148 } 00149 00150 /* ---------------------------------------------------------------------- 00151 * clones a list. 00152 * 00153 * This doesn't clone the items. 00154 * 00155 * @param l the list that has to be cloned. 00156 * @returns a newly allocated list after cloning. 00157 */ 00158 List listClone(List l) 00159 { 00160 List m = NULL; 00161 00162 if ( l == NULL ) 00163 return( NULL ); 00164 00165 m = newListCell; 00166 00167 m->item = l->item; 00168 m->next = listClone( l->next ); 00169 00170 return( m ); 00171 } 00172 00173 /* ---------------------------------------------------------------------- 00174 Clones a list, performing a deep copy of all items via P. 00175 */ 00176 List listDeepClone(List l, PointerFunction *p) 00177 { 00178 List m; 00179 00180 if (l == NULL) { 00181 return NULL; 00182 } 00183 00184 m = newListCell; 00185 m->item = (*p)(l->item); 00186 m->next = listDeepClone(l->next, p); 00187 00188 return m; 00189 } 00190 00191 /* ---------------------------------------------------------------------- 00192 * set list-items of dst to those of src by reusing old buckets. 00193 * 00194 * It works as follows: 00195 * - if dst has more buckets than src then these are freed 00196 * - if dst has less buckets than src then new once are allocated 00197 * - if dst is NULL then listCopy is equivalent to listClone 00198 * - if src is NULL then listCopy is equivalent to listDelete 00199 * 00200 * @param dst the resulting list 00201 * @param src the originating list 00202 * @returns the dst List 00203 */ 00204 List listCopy(List dst, List src) 00205 { 00206 List ldst, lsrc, prev; 00207 00208 /* empty dst = listClone */ 00209 if (!dst) { 00210 return listClone(src); 00211 } 00212 00213 /* empty src = listDelete */ 00214 if (!src) { 00215 listDelete(dst); 00216 return NULL; 00217 } 00218 00219 /* real work */ 00220 for (prev = NULL, ldst = dst, lsrc = src; 00221 ldst && lsrc; 00222 prev = ldst, ldst = ldst->next, lsrc = lsrc->next) 00223 { 00224 ldst->item = lsrc->item; 00225 } 00226 00227 /* more buckets in dst than in src */ 00228 if (ldst) { 00229 listDelete(ldst); 00230 00231 /* prev should never bee NULL here because dst != NULL */ 00232 prev->next = NULL; 00233 } else { 00234 prev->next = listClone(lsrc); 00235 } 00236 00237 return dst; 00238 } 00239 00240 /* ---------------------------------------------------------------------- 00241 * appends a list to another list. 00242 * 00243 * @param front a list to whose end another list rear is appended. 00244 * @param rear a list which is appended to the tail of the front list 00245 * @returns the new list after appending. 00246 */ 00247 List listAppendList(List front, List rear) 00248 00249 { 00250 List l; 00251 00252 if ( front == NULL ) 00253 return( rear ); 00254 00255 l = front; 00256 while ( l->next != NULL ) 00257 l = l->next; 00258 l->next = rear; 00259 return( front ); 00260 } 00261 00262 /* ---------------------------------------------------------------------- 00263 * appends an item to the end of a list. 00264 * 00265 * @param l the list to which an item has to be appended. 00266 * @param item the item that has to be appended to the end of the list l. 00267 * @returns the new list after appending. 00268 */ 00269 List listAppendElement(List l, Pointer item) 00270 { 00271 List m, n; 00272 00273 m = newListCell; 00274 00275 m->next = NULL; 00276 m->item = item; 00277 00278 if (l == NULL) { 00279 return (m); 00280 } else { 00281 n = l; 00282 while (n->next != NULL) 00283 n = n->next; 00284 n->next = m; 00285 return (l); 00286 } 00287 } 00288 00289 /* ---------------------------------------------------------------------- 00290 * prepends an item to a list. 00291 * 00292 * @param l the list to which an item has to be prepended. 00293 * @param item the item that has to be prepended to the list l. 00294 * @returns the new list after prepending. 00295 */ 00296 List listPrependElement(List l, Pointer item) 00297 { 00298 List m; 00299 00300 m = newListCell; 00301 00302 m->next = l; 00303 m->item = item; 00304 00305 return( m ); 00306 } 00307 00308 /* ---------------------------------------------------------------------- 00309 * appends a couple of items to the end of a list. 00310 * 00311 * @param oldList the list to which a couple of items are to be appended. 00312 * @param ... the list of items are to be appended to the end of the list. 00313 */ 00314 List listAppendElements(List oldList, ...) 00315 { 00316 va_list ap; 00317 Pointer item; 00318 List newList = oldList; 00319 00320 va_start(ap, oldList); 00321 while ((item = va_arg(ap, Pointer)) != NULL) { 00322 newList = listAppendElement(newList, item); 00323 } 00324 va_end(ap); 00325 00326 return newList; 00327 } 00328 00329 /* ---------------------------------------------------------------------- 00330 * prepends a couple of items to the end of a list. 00331 * 00332 * @param oldList the list to which the items are prepended. 00333 * @param ... the list of items that are to be prepended to the list l. 00334 * @returns the new list after prepending. 00335 */ 00336 List listPrependElements(List oldList, ...) 00337 { 00338 va_list ap; 00339 Pointer item; 00340 List newList = oldList; 00341 00342 va_start(ap, oldList); 00343 while ((item = va_arg(ap, Pointer)) != NULL) { 00344 newList = listPrependElement(newList, item); 00345 } 00346 va_end(ap); 00347 00348 return newList; 00349 } 00350 00351 /* ---------------------------------------------------------------------- 00352 * inserts an item keeping an order defined by f. 00353 * 00354 * @param list the list into which a specified item has to be inserted. 00355 * @param item the item that has to be inserted into the list l. 00356 * @param f the function that defines the ordering of the during insertion. 00357 * @returns the new list after insertion operation. 00358 */ 00359 List listInsertSorted(List list, Pointer item, BooleanFunction *f) 00360 { 00361 List l, prev, newList; 00362 00363 newList = newListCell; 00364 00365 newList->item = item; 00366 newList->next = NULL; 00367 00368 for (prev = NULL, l = list; l; prev = l, l = l->next) { 00369 if ((*f) (item, l->item)) 00370 break; 00371 } 00372 newList->next = l; 00373 if (prev) { 00374 prev->next = newList; 00375 return (list); 00376 } else { 00377 return (newList); 00378 } 00379 } 00380 00381 /* ---------------------------------------------------------------------- 00382 * inserts an item keeping an order defined by f and some extra data. 00383 * 00384 * @param list the list into which a specified item has to be inserted. 00385 * @param item the item that has to be inserted into the list l. 00386 * @param 'f' the function that defines the ordering of the during insertion. 00387 * @param clientData the data that determines the ordering along with the function 'f' 00388 * @returns the new list after insertion operation. 00389 */ 00390 List listInsertSortedWithData(List list, Pointer item, BooleanFunction * f, 00391 Pointer clientData) 00392 { 00393 List l, prev, newList; 00394 00395 newList = newListCell; 00396 00397 newList->item = item; 00398 newList->next = NULL; 00399 00400 for (prev = NULL, l = list; l; prev = l, l = l->next) { 00401 if ((*f) (item, l->item, clientData)) 00402 break; 00403 } 00404 newList->next = l; 00405 if (prev) { 00406 prev->next = newList; 00407 return (list); 00408 } else { 00409 return (newList); 00410 } 00411 } 00412 00413 /* ---------------------------------------------------------------------- 00414 * adds an item to the list if and only if it is not already present. 00415 * 00416 * @param l the list to which the specified item has to be added. 00417 * @param item the item that has to be added to the list l. 00418 * @returns the new list after the addition of the item if its unique. 00419 */ 00420 List listAddUniqueElement(List l, Pointer item) 00421 { 00422 if(listContains(l,item)) { 00423 return l; 00424 } else { 00425 return listAppendElement(l,item); 00426 } 00427 } 00428 00429 /* ---------------------------------------------------------------------- 00430 * retrieves number of items in the list. 00431 * 00432 * @param l the list whose size has to be retrieved. 00433 * @returns the total number of items in the list l. 00434 */ 00435 int listSize(List l) 00436 { 00437 int i = 0; 00438 00439 while ( l != NULL ) { 00440 i++; 00441 l = l->next; 00442 } 00443 return( i ); 00444 } 00445 00446 /* ---------------------------------------------------------------------- 00447 * returns nth item in list. 00448 * 00449 * @param l the list whose 'n'th item has to be retrieved. 00450 * @param n the number that idicates the item that has to be retrieved. 00451 * @returns the item in the 'n'th position of the list. 00452 */ 00453 Pointer listNthElement(List l, int n) 00454 { 00455 if ( l == NULL || n < 1 ) { 00456 fprintf( stderr, "WARNING: listNthElement: list is empty or n < 1\n" ); 00457 abort(); 00458 } else if ( n == 1 ) { 00459 return( l->item ); 00460 } else { 00461 return( listNthElement( l->next, n - 1 ) ); 00462 } 00463 } 00464 00465 /* ---------------------------------------------------------------------- 00466 * returns last item in list. 00467 * 00468 * @param l the list from which the last item has to be retrieved. 00469 * @returns the last item of the list l. 00470 */ 00471 Pointer listLastElement(List l ) 00472 { 00473 if ( l == NULL ) { 00474 fprintf( stderr, "WARNING: listLastElement: list is empty\n" ); 00475 abort(); 00476 } else { 00477 while ( l->next != NULL ) 00478 l = l->next; 00479 return( l->item ); 00480 } 00481 } 00482 00483 /* ---------------------------------------------------------------------- 00484 * checks if the list contains a particular item. 00485 * 00486 * @param l the list in which the existance of the specified item has to be checked. 00487 * @param p specifies the item that has to be checked for in the list l. 00488 * @returns \a TRUE if the list contains the item or \a FALSE otherwise. 00489 */ 00490 Boolean listContains(List l, Pointer p) 00491 { 00492 for ( ; l != NULL; l = l->next ) 00493 if ( l->item == p ) 00494 return( TRUE ); 00495 return( FALSE ); 00496 } 00497 00498 /* ---------------------------------------------------------------------- 00499 * calls function `f' for each list element. 00500 * 00501 * @param l the list in which the function 'f' is called. 00502 * @param f the function which is called for each element in the list l. 00503 */ 00504 void listForEach(List l, VoidFunction *f) 00505 { 00506 while ( l != NULL) { 00507 (*f)( l->item ); 00508 l = l->next; 00509 } 00510 } 00511 00512 /* ---------------------------------------------------------------------- 00513 * like listForEach, but frees list, list becomes inaccessible. 00514 * 00515 * @param l the list in which the function 'f' has to be called. 00516 * @param f the function that is called for each element in the list l. 00517 */ 00518 void listForEachDelete(List l, VoidFunction *f) 00519 { 00520 List m; 00521 00522 while ( l != NULL ) { 00523 (*f)( l->item ); 00524 m = l; 00525 l = l->next; 00526 00527 freeListCell( m ); 00528 } 00529 } 00530 00531 /* ---------------------------------------------------------------------- 00532 * filters list, returns new (sub-)list. 00533 * 00534 * @param l the list on which the function is evaluated. 00535 * @param f the function that is evaluated in the list l to generate a (sub-) list 00536 * @returns an independent list consisting of all the elements of the given list l that make 00537 * function 'f' evaluate to \a TRUE 00538 */ 00539 List listFilter(List l, BooleanFunction *f) 00540 { 00541 List m = NULL; 00542 00543 while ( l != NULL) { 00544 if ( (*f)( l->item ) ) { 00545 m = listAppendElement( m, l->item ); 00546 } 00547 l = l->next; 00548 } 00549 return( m ); 00550 } 00551 00552 /* ---------------------------------------------------------------------- 00553 * frees list, does NOT free elements. 00554 * 00555 * @param l the list that needs to be freed. 00556 * @returns nothing. 00557 */ 00558 void listDelete(List l) 00559 { 00560 List m; 00561 while ( l != NULL ) { 00562 m = l; 00563 l = l->next; 00564 00565 freeListCell( m ); 00566 } 00567 } 00568 00569 /* ---------------------------------------------------------------------- 00570 * deletes all occurences of item from list. 00571 * 00572 * @param l the list from which all the occurances of a specified item has to be deleted. 00573 * @param p the particular item whose occurances in the list l has to be deleted. 00574 * @returns the new list after deleting the item from the list. 00575 */ 00576 List listDeleteElement(List l, Pointer p) 00577 { 00578 List m, n; 00579 00580 if ( l == NULL ) 00581 return( l ); 00582 00583 if ( l->item == p ) { 00584 m = l->next; 00585 00586 freeListCell( l ); 00587 return( listDeleteElement( m, p ) ); 00588 } else { 00589 m = l; 00590 while ( m->next != NULL ) { 00591 while ( m->next != NULL && m->next->item != p ) 00592 m = m->next; 00593 00594 if ( m->next == NULL ) { 00595 return( l ); 00596 } else { 00597 n = m->next; 00598 m->next = m->next->next; 00599 00600 freeListCell( n ); 00601 } 00602 } 00603 return( l ); 00604 } 00605 } 00606 /* ---------------------------------------------------------------------- 00607 * deletes the last item from the list. 00608 * 00609 * @param l the list from which the last item has to be deleted. 00610 * @returns the new list after deleting the last item form the list l. 00611 */ 00612 List listDeleteLastElement(List l) 00613 { 00614 List m; 00615 List orig; 00616 00617 if ( l == NULL ) 00618 return( l ); 00619 00620 if(l->next == NULL){ 00621 freeListCell( l ); 00622 return NULL; 00623 } else { 00624 orig=l; 00625 while ( l->next != NULL ) { 00626 m = l; 00627 l = l->next; 00628 } 00629 freeListCell( m->next ); 00630 m->next = NULL; 00631 00632 return( orig ); 00633 } 00634 } 00635 00636 /* ---------------------------------------------------------------------- 00637 * converts a list into a vector. 00638 * 00639 * @param l the list that has to be converted into a vector v. 00640 * @returns the vector v corresponding to the list l. 00641 */ 00642 Vector listToVector(List l) 00643 { 00644 Vector v; 00645 List ll; 00646 int i; 00647 00648 if (l == NULL) 00649 return NULL; 00650 00651 v = vectorNew(listSize(l)); 00652 for (ll=l, i=0; ll != NULL; ll=ll->next, i++) { 00653 vectorSetElement(v, ll->item, i); 00654 } 00655 00656 return v; 00657 } 00658 00659 /* ---------------------------------------------------------------------- 00660 * find a particular item in a list . 00661 * 00662 * @param l the list from which the specified item has to be found. 00663 * @param item the item that has to be found from the list l. 00664 * @returns the index of the item if found else zero. 00665 */ 00666 int listIndex(List l, Pointer item) 00667 { 00668 00669 int result = 1; 00670 List m = l; 00671 00672 for (m = l; m != NULL; m = m->next, result++) { 00673 if (m->item == item) { 00674 return result; 00675 } 00676 } 00677 00678 return 0; 00679 00680 } 00681 00682 /* ---------------------------------------------------------------------- 00683 * compare two lists item per item. 00684 * 00685 * @param list1 the first list whose items are to be compared. 00686 * @param list2 the second list whose items are compared with the list 1. 00687 * @returns \a TRUE if the items are all equal and \a FALSE otherwise. 00688 */ 00689 Boolean listIsEqual(List list1, List list2) 00690 { 00691 List l, m; 00692 00693 if (listSize(list1) != listSize(list2)) 00694 return FALSE; 00695 00696 for (l = list1; l != NULL; l = l->next) { 00697 for (m = list2; m != NULL; m = m->next) { 00698 if (l->item != m->item) 00699 return FALSE; 00700 } 00701 } 00702 00703 return TRUE; 00704 } 00705 00706 /* ---------------------------------------------------------------------- 00707 * sorts a list, using a user-specified compare function. 00708 * 00709 * @param l the list that has to be sorted using the function 'f' 00710 * @param f the compare function that is used for the sorting of the list l. 00711 * @returns the new list after sorting using the function 'f' 00712 */ 00713 List listSort(List l, BooleanFunction *f) 00714 { 00715 if (l) { 00716 Vector v = listToVector(l); 00717 vectorSort(v, f); 00718 l = vectorToList(v); 00719 vectorDelete(v); 00720 return l; 00721 } else { 00722 return NULL; 00723 } 00724 } 00725 00726 /* ---------------------------------------------------------------------- 00727 * sorts a list, using a user-specified compare function and some data. 00728 * 00729 * @param l the list that has to be sorted using the function 'f' 00730 * @param f the compare function that is used for the sorting of the list l. 00731 * @param data the data that defines the sorting along with the function 'f' 00732 * @returns the new list after sorting using the function 'f' and the data. 00733 */ 00734 List listSortWithData(List l, BooleanFunction *f, void *data) 00735 { 00736 if (l) { 00737 Vector v = listToVector(l); 00738 vectorSortWithData(v, f, data); 00739 l = vectorToList(v); 00740 vectorDelete(v); 00741 return l; 00742 } else { 00743 return NULL; 00744 } 00745 } 00746 00747 /* ---------------------------------------------------------------------- 00748 * return a new reverse list. 00749 * 00750 * @param l the list whose data items are to be reversed. 00751 * @returns a new list after reversing the list l. 00752 */ 00753 List listReverse(List l) 00754 { 00755 List reverse = NULL; 00756 00757 while (l) { 00758 reverse = listPrependElement(reverse, listElement(l)); 00759 l = listNext(l); 00760 } 00761 00762 return reverse; 00763 } 00764 /* ---------------------------------------------------------------------- */ 00765 /** @} */ 00766 00767