Changeset 454 for trunk/psLib/src/sysUtils/psDList.c
- Timestamp:
- Apr 19, 2004, 11:01:12 AM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/sysUtils/psDList.c (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/sysUtils/psDList.c
r453 r454 1 /* 2 * Minimal support for doubly linked lists 3 */ 4 #include <stdlib.h> 5 #include <stdio.h> 6 #include <assert.h> 7 #include "psLib.h" 8 9 static psDlistElem *dlistElemAlloc(void) 10 { 11 return(psAlloc(sizeof(psDlistElem))); 12 } 13 14 static void dlistElemFree(psDlistElem *elem) 15 { 16 psFree(elem); 17 } 18 19 /*****************************************************************************/ 20 21 psDlist *psDlistAlloc(void *data) // initial data item; may be NULL 22 { 23 psDlist *list = psAlloc(sizeof(psDlist)); 24 25 list->n = 0; 26 list->head = list->tail = NULL; 27 list->iter = NULL; 28 if (data != NULL) 29 { 30 psDlistAdd(list, data, PS_DLIST_TAIL); 31 } 32 33 return list; 34 } 35 36 void psDlistFree(psDlist *list, // list to destroy 37 void (*elemFree)(void *)) // destructor for data on list 38 { 39 if (list == NULL) 40 { 41 return; 42 } 43 44 psDlistElem *ptr = list->head; 45 while (ptr != NULL) 46 { 47 psDlistElem *next = ptr->next; 48 49 if (elemFree == NULL) { 50 psMemDecrRefCounter(ptr->data); 51 } else { 52 elemFree(psMemDecrRefCounter(ptr->data)); 53 } 54 dlistElemFree(ptr); 55 56 ptr = next; 57 } 58 59 psFree(list); 60 } 61 62 /*****************************************************************************/ 63 /* 64 * Add an element to a list 65 */ 66 psDlist *psDlistAdd(psDlist *list, // list to add to; may be NULL 67 void *data, // data to add 68 int where) // where to add data. PS_DLIST_HEAD, 69 // PS_DLIST_TAIL, or an integer 70 { 71 psDlistElem *elem = dlistElemAlloc(); 72 73 if (list == NULL) 74 { 75 list = psDlistAlloc(NULL); 76 } 77 78 if (where > list->n) 79 { // XXX need better diagnostic here 80 fprintf(stderr, "Invalid index %d (only %d elements)\n", 81 where, list->n); 82 dlistElemFree(elem); // cleanup 83 84 return list; 85 } 86 87 if (where == PS_DLIST_HEAD) 88 { // easy 89 elem->prev = NULL; 90 elem->next = list->head; 91 elem->data = psMemIncrRefCounter(data); 92 93 if (list->head != NULL) { 94 list->head->prev = elem; 95 } 96 97 list->head = elem; 98 if (list->tail == NULL) { 99 list->tail = elem; 100 } 101 list->n++; 102 } else if (where == PS_DLIST_TAIL) 103 { // also easy 104 elem->prev = list->tail; 105 elem->next = NULL; 106 elem->data = psMemIncrRefCounter(data); 107 108 if (list->tail != NULL) { 109 list->tail->next = elem; 110 } 111 112 list->tail = elem; 113 if (list->head == NULL) { 114 list->head = elem; 115 } 116 list->n++; 117 } else 118 { // XXX 119 fprintf(stderr, "Insertion into psDlists is not yet supported\n"); 120 return psDlistAdd(list, data, PS_DLIST_TAIL); 121 } 122 123 return list; 124 } 125 126 /*****************************************************************************/ 127 128 psDlist *psDlistAppend(psDlist *list, // list to add to; may be NULL 129 void *data) // data to add at end 130 { 131 return psDlistAdd(list, data, PS_DLIST_TAIL); 132 } 133 134 /*****************************************************************************/ 135 /* 136 * Remove an element from a list 137 */ 138 void *psDlistRemove(psDlist *list, // list to remove element from 139 void *data, // data item to remove (or NULL) 140 int which) // index of item, if known. 141 // PS_DLIST_UNKNOWN, or PS_DLIST_HEAD, 142 // or PS_DLIST_TAIL 143 { 144 psDlistElem *elem = NULL; // element to remove 145 assert (list != NULL); 146 147 if (data != NULL) 148 { 149 assert (which == PS_DLIST_UNKNOWN); 150 151 int i = 0; // index 152 for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next, i++) { 153 if (ptr->data == data) { 154 return psDlistRemove(list, NULL, i); 155 } 156 } 157 158 psTrace("utils.dlist.remove", 5, "Failed to find 0x%x on psDlist 0x%x", data, list); 159 160 return NULL; 161 } 162 163 if (which == PS_DLIST_HEAD || which == 0) 164 { 165 if (list->head == NULL) { 166 return NULL; 167 } else { 168 elem = list->head; 169 170 if (list->head->next != NULL) { 171 list->head->next->prev = NULL; 172 } 173 list->head = list->head->next; 174 list->n--; 175 176 if (list->head == NULL) { 177 list->tail = NULL; 178 } 179 } 180 } else if (which == PS_DLIST_TAIL || which == list->n - 1) 181 { 182 if (list->tail == NULL) { 183 return NULL; 184 } else { 185 elem = list->tail; 186 if (list->tail->prev != NULL) { 187 list->tail->prev->next = NULL; 188 } 189 list->tail = list->tail->prev; 190 list->n--; 191 192 if (list->tail == NULL) { 193 list->head = NULL; 194 } 195 } 196 } else if (which != PS_DLIST_UNKNOWN) 197 { // an index in the middle of the list 198 assert (which != 0 && which != list->n - 1); 199 200 if (which < 0 || which >= list->n) { // out of bounds 201 psError(__func__, PS_ERR_BAD_INDEX, 1, "Index %d is not in range [0..%d] for list 0x%x", which, list->n, 202 list); 203 return NULL; 204 } 205 206 int i = 0; // index 207 for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next, i++) { 208 if (i == which) { 209 ptr->prev->next = ptr->next; 210 ptr->next->prev = ptr->prev; 211 212 elem = ptr; 213 } 214 } 215 } 216 /* 217 * OK, delete list element and return the data 218 */ 219 assert (elem != NULL); 220 data = elem->data; 221 dlistElemFree(elem); 222 223 return psMemDecrRefCounter(data); 224 } 225 226 /*****************************************************************************/ 227 /* 228 * Retrieve an element from the list, or iterate over list. 229 * 230 * If which is psDlist{Next,Prev} return the next/previous 231 * data and move the iteration cursor 232 * 233 * If which is psDlist{Head,Tail} initialise the iteration pointer 234 * and return the head/tail 235 * 236 * Otherwise, return the desired element 237 */ 238 #define ITER_INIT_HEAD ((void *)1) // next iteration should return head 239 #define ITER_INIT_TAIL ((void *)2) // next iteration should return tail 240 241 void *psDlistGet( 242 const psDlist *list, // list to retrieve element from 243 int which) // index of item, or PS_DLIST_NEXT, 244 // or PS_DLIST_PREV 245 { 246 assert (list != NULL); 247 248 switch (which) { 249 case PS_DLIST_HEAD: // easy 250 ((psDlist *)list)->iter = ITER_INIT_HEAD; 251 return (list->head == NULL) ? NULL : list->head->data; 252 case PS_DLIST_TAIL: // also easy 253 ((psDlist *)list)->iter = ITER_INIT_TAIL; 254 return (list->tail == NULL) ? NULL : list->tail->data; 255 case PS_DLIST_PREV: // use iterator 256 case PS_DLIST_NEXT: 257 if (list->iter == NULL) { 258 return NULL; 259 } else if (list->iter == ITER_INIT_HEAD) { 260 ((psDlist *)list)->iter = list->head; 261 } else if (list->iter == ITER_INIT_TAIL) { 262 ((psDlist *)list)->iter = list->tail; 263 } else if (which == PS_DLIST_PREV) { 264 ((psDlist *)list)->iter = list->iter->prev; 265 } else if (which == PS_DLIST_NEXT) { 266 ((psDlist *)list)->iter = list->iter->next; 267 } else { 268 fprintf(stderr,"You cannot get here\n"); 269 abort(); 270 } 271 272 if (list->iter == NULL) { 273 return NULL; 274 } 275 return list->iter->data; // XXX what if data is NULL? 276 277 break; 278 default: // XXX 279 fprintf(stderr, 280 "Retrieval from psDlists by index is not yet supported\n"); 281 return NULL; 282 } 283 } 284 285 /*****************************************************************************/ 286 /* 287 * Some wrappers for those iteration calls using psDlistGet. 288 * 289 * First a call to set the iteration pointer to the head of the list 290 */ 291 void psDlistSetIterator(psDlist *list, // the list in question 292 int where, // where on the list should I start? 293 int which) // @notused@ the desired iterator 294 { 295 if (where != PS_DLIST_HEAD && where != PS_DLIST_TAIL) 296 { 297 psError(__func__, PS_ERR_UNKNOWN, 1, "Invalid where argument: %d; assuming PS_DLIST_HEAD", where); 298 where = PS_DLIST_HEAD; 299 } 300 301 psDlistGet(list, where); // initialise iterator at head/tail 302 } 303 304 /* 305 * and now return the previous/next element of the list 306 */ 307 void *psDlistGetNext(psDlist *list, // the list in question 308 int which) // @notused@ the desired iterator 309 { 310 return psDlistGet(list, PS_DLIST_NEXT); 311 } 312 313 void *psDlistGetPrev(psDlist *list, // the list in question 314 int which) // @notused@ the desired iterator 315 { 316 return psDlistGet(list, PS_DLIST_PREV); 317 } 318 319 /*****************************************************************************/ 320 /* 321 * Convert a psDlist to/from a psVoidPtrArray 322 */ 323 psVoidPtrArray *psDlistToArray(psDlist *restrict dlist) 324 { 325 if (dlist == NULL) { 326 return NULL; 327 } 328 329 psVoidPtrArray *restrict arr = psVoidPtrArrayAlloc(dlist->n, dlist->n); 330 331 psDlistElem *ptr = dlist->head; 332 for (int i = 0, n = dlist->n; i < n; i++) { 333 arr->arr[i] = ptr->data; 334 335 ptr->data = NULL; 336 ptr = ptr->next; 337 } 338 339 psDlistFree(dlist, NULL); 340 341 return arr; 342 } 343 344 psDlist *psArrayToDlist(psVoidPtrArray *arr) 345 { 346 psDlist *list = psDlistAlloc(NULL); // list of elements 347 348 for (int i = 0, n = arr->n; i < n; i++) { 349 psDlistAppend(list, 350 psMemDecrRefCounter(arr->arr[i])); // it's already Incr 351 arr->arr[i] = NULL; 352 } 353 354 psVoidPtrArrayFree(arr, NULL); 355 356 return list; 357 }
Note:
See TracChangeset
for help on using the changeset viewer.
