00001 /* Copyright (c) 2005 by John M. Boyer, All Rights Reserved. Please see 00002 * License.txt for use and redistribution license. */ 00003 /* Copyright (c) 1997-2003 by John M. Boyer, All Rights Reserved. 00004 This code may not be reproduced in whole or in part without 00005 the written permission of the author. */ 00006 00007 #define _LISTCOLL_C 00008 00009 #include "appconst.h" 00010 #include "listcoll.h" 00011 #include <stdlib.h> 00012 00013 /***************************************************************************** 00014 The data structure defined by this module manages a set of N objects 00015 arranged as a collection of circular lists, each containing distinct 00016 elements from the set. 00017 00018 On construction, LCNew() creates an array of N nodes, each containing a 00019 prev and next pointer. The identity of the node is given by its array index. 00020 Each node's prev and next pointers are set to NIL, indicating that the node 00021 is not currently part of a list. LCReset() can be called to reset all 00022 pointers to NIL. 00023 00024 The function LCFree() deallocates the collection of lists and clears the 00025 pointer variable used to pass the collection. 00026 00027 An empty list is indicated by NIL. To begin a list with node I, call 00028 LCPrepend() or LCAppend() with the NIL list and with I as the node. The prev 00029 and next pointers in node I are set to I and I is returned as the head of 00030 the list. 00031 00032 Future calls to LCPrepend() add a node J as the new first element of the list, 00033 so the list given as input is pointed to by J's next, and J is returned as 00034 the head of the list. 00035 00036 Future calls to LCAppend() add a node J as the new last element, so the prev 00037 pointer of the list given as input will indicate node J, and the input list 00038 is returned as the head of the list. 00039 00040 The function LCDelete() removes a node I from a list L. If node I is in the 00041 list alone, then its pointers are set to NIL, and NIL is returned as the list. 00042 If node I is not alone in the list, but it is the head of the list (in other 00043 words, I is equal to L), then L's sucessor is returned as the new head of the 00044 list. Whether or not I equals L, node I is deleted by joining its predecessor 00045 and successor nodes. 00046 00047 LCCopy() copies the contents of one collection to another if both are of 00048 equal size. 00049 00050 LCGetNext() is used for forward iteration through a list in the collection. 00051 The expected iteration pattern is to process the node one has then call 00052 LCGetNext() to get the next node, so if the result of LCGetNext() would be the 00053 head of the list, then NIL is returned instead. This simplifies most 00054 coding operations involving LCGetNext(). 00055 00056 LCGetPrev() is used for backward iteration through a list in the collection. 00057 The expected iteration pattern is that the last list element will be obtained 00058 by an initial call to LCGetPrev() with theNode equal to NIL. This call 00059 should appear outside of the iteration loop. The iteration loop then 00060 proceeds while the current node is not NIL. The loop body processes the 00061 current node, then LCGetPrev() is called with theNode equal to the current 00062 node. LCGetPrev() returns NIL if theNode is equal to theList. Otherwise, 00063 the predecessor of theNode is returned. 00064 00065 *****************************************************************************/ 00066 00067 /***************************************************************************** 00068 LCNew() 00069 *****************************************************************************/ 00070 listCollectionP LCNew (int N) 00071 { 00072 listCollectionP theListColl = NULL; 00073 if (N <= 0) 00074 return theListColl; 00075 theListColl = (listCollectionP) malloc (sizeof (listCollectionRec)); 00076 if (theListColl != NULL) 00077 00078 { 00079 theListColl->List = (lcnode *) malloc (N * sizeof (lcnode)); 00080 if (theListColl->List == NULL) 00081 00082 { 00083 free (theListColl); 00084 theListColl = NULL; 00085 } 00086 00087 else 00088 00089 { 00090 theListColl->N = N; 00091 LCReset (theListColl); 00092 } 00093 } 00094 return theListColl; 00095 } 00096 00097 00098 /***************************************************************************** 00099 LCFree() 00100 *****************************************************************************/ 00101 void LCFree (listCollectionP * pListColl) 00102 { 00103 if (pListColl == NULL || *pListColl == NULL) 00104 return; 00105 if ((*pListColl)->List != NULL) 00106 free ((*pListColl)->List); 00107 free (*pListColl); 00108 *pListColl = NULL; 00109 } 00110 00111 00112 #ifndef SPEED_MACROS 00113 00114 /***************************************************************************** 00115 LCReset() 00116 *****************************************************************************/ 00117 void LCReset (listCollectionP listColl) 00118 { 00119 int I; 00120 for (I = 0; I < listColl->N; I++) 00121 listColl->List[I].prev = listColl->List[I].next = NIL; 00122 } 00123 00124 00125 /***************************************************************************** 00126 LCCopy() 00127 *****************************************************************************/ 00128 void LCCopy (listCollectionP dst, 00129 listCollectionP src) 00130 { 00131 int I; 00132 if (dst == NULL || src == NULL || dst->N != src->N) 00133 return; 00134 for (I = 0; I < dst->N; I++) 00135 dst->List[I] = src->List[I]; 00136 } 00137 00138 00139 /***************************************************************************** 00140 LCGetNext() 00141 *****************************************************************************/ 00142 int LCGetNext (listCollectionP listColl, 00143 int theList, 00144 int theNode) 00145 { 00146 int next; 00147 if (listColl == NULL || theList == NIL || theNode == NIL) 00148 return NIL; 00149 next = listColl->List[theNode].next; 00150 return next == theList ? NIL : next; 00151 } 00152 00153 00154 /***************************************************************************** 00155 LCGetPrev() 00156 *****************************************************************************/ 00157 int LCGetPrev (listCollectionP listColl, 00158 int theList, 00159 int theNode) 00160 { 00161 if (listColl == NULL || theList == NIL) 00162 return NIL; 00163 if (theNode == NIL) 00164 return listColl->List[theList].prev; 00165 if (theNode == theList) 00166 return NIL; 00167 return listColl->List[theNode].prev; 00168 } 00169 00170 00171 /***************************************************************************** 00172 LCPrepend() 00173 *****************************************************************************/ 00174 int LCPrepend (listCollectionP listColl, 00175 int theList, 00176 int theNode) 00177 { 00178 int newList = LCAppend (listColl, theList, theNode); 00179 00180 /* If the append worked, then theNode is last, which in a circular 00181 * list is the direct predecessor of the list head node, so we 00182 * just back up one. For singletons, the result is unchanged. */ 00183 if (newList != NOTOK) 00184 newList = listColl->List[newList].prev; 00185 return newList; 00186 } 00187 00188 00189 /***************************************************************************** 00190 LCAppend() 00191 *****************************************************************************/ 00192 int LCAppend (listCollectionP listColl, 00193 int theList, 00194 int theNode) 00195 { 00196 00197 /* If the given list is empty, then the given node becomes the 00198 * singleton list output */ 00199 if (theList == NIL) 00200 00201 { 00202 listColl->List[theNode].prev = listColl->List[theNode].next = theNode; 00203 theList = theNode; 00204 } 00205 00206 /* Otherwise, make theNode the predecessor of head node of theList, 00207 * which is where the last node goes in a circular list. */ 00208 00209 else 00210 00211 { 00212 int pred = listColl->List[theList].prev; 00213 listColl->List[theList].prev = theNode; 00214 listColl->List[theNode].next = theList; 00215 listColl->List[theNode].prev = pred; 00216 listColl->List[pred].next = theNode; 00217 } 00218 00219 /* Return the list (only really important if it was NIL) */ 00220 return theList; 00221 } 00222 00223 00224 /***************************************************************************** 00225 LCDelete() 00226 *****************************************************************************/ 00227 int LCDelete (listCollectionP listColl, 00228 int theList, 00229 int theNode) 00230 { 00231 00232 /* If the list is a singleton, then NIL its pointers and 00233 * return NIL for theList */ 00234 if (listColl->List[theList].next == theList) 00235 00236 { 00237 listColl->List[theList].prev = listColl->List[theList].next = NIL; 00238 theList = NIL; 00239 } 00240 00241 /* Join predecessor and successor, dropping theNode from the list. 00242 * If theNode is the head of the list, then return the successor as 00243 * the new head node. */ 00244 00245 else 00246 00247 { 00248 int pred = listColl->List[theNode].prev, 00249 succ = listColl->List[theNode].next; 00250 listColl->List[pred].next = succ; 00251 listColl->List[succ].prev = pred; 00252 listColl->List[theNode].prev = listColl->List[theNode].next = NIL; 00253 if (theList == theNode) 00254 theList = succ; 00255 } 00256 return theList; 00257 } 00258 00259 00260 #endif // SPEED_MACROS