Changeset 506 for trunk/psLib/src/sysUtils/psDList.c
- Timestamp:
- Apr 22, 2004, 2:19:42 PM (22 years ago)
- File:
-
- 1 edited
-
trunk/psLib/src/sysUtils/psDList.c (modified) (11 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/psLib/src/sysUtils/psDList.c
r484 r506 6 6 * @author Robert Daniel DeSonia, MHPCC 7 7 * 8 * @version $Revision: 1. 4$ $Name: not supported by cvs2svn $9 * @date $Date: 2004-04-2 1 00:15:17$8 * @version $Revision: 1.5 $ $Name: not supported by cvs2svn $ 9 * @date $Date: 2004-04-23 00:19:42 $ 10 10 * 11 11 * Copyright 2004 Maui High Performance Computing Center, University of Hawaii … … 13 13 14 14 #include <stdlib.h> 15 #include <stdbool.h> 15 16 #include <stdio.h> 16 #include <assert.h> 17 #include <pthread.h> // we need a mutex to make this stuff thread safe. 18 17 19 #include "psError.h" 18 20 #include "psAbort.h" … … 21 23 #include "psTrace.h" 22 24 25 #define ITER_INIT_HEAD ((void *)1) // next iteration should return head 26 #define ITER_INIT_TAIL ((void *)2) // next iteration should return tail 27 28 // private functions. 29 psDlistElem* dlistGetIterator(psDlist* list); 30 int dlistGetIteratorIndex(psDlist* list); 31 void dlistSetIterator(psDlist *list, int where, bool lockList); 32 33 34 23 35 static psDlistElem *dlistElemAlloc(void) 24 36 { … … 35 47 psDlist *list = psAlloc(sizeof(psDlist)); 36 48 37 list-> n= 0;49 list->size = 0; 38 50 list->head = list->tail = NULL; 39 list->iter = NULL; 40 list->iterIndex = 0; 51 list->iter = ITER_INIT_HEAD; 52 list->iterIndex = PS_DLIST_HEAD; 53 pthread_mutex_init(&(list->lock),NULL) 54 ; 55 41 56 if (data != NULL) { 42 57 psDlistAdd(list, data, PS_DLIST_TAIL); … … 51 66 return; 52 67 } 68 69 pthread_mutex_lock(&list->lock) 70 ; 53 71 54 72 for(psDlistElem *ptr = list->head; ptr != NULL; ) { … … 65 83 } 66 84 85 pthread_mutex_unlock(&list->lock) 86 ; 87 88 pthread_mutex_destroy(&list->lock) 89 ; 90 67 91 psFree(list); 68 92 } … … 70 94 psDlist *psDlistAdd(psDlist *list, void *data, int where) 71 95 { 72 psDlistElem *elem = dlistElemAlloc(); 96 psDlistElem* position; 97 psDlistElem* elem = dlistElemAlloc(); 73 98 74 99 if (list == NULL) { … … 76 101 } 77 102 78 if (where > list->n) { 79 psError(__FILE__, "Invalid index %d (only %d elements in psDList); assuming tail.", where, list->n); 103 pthread_mutex_lock(&list->lock) 104 ; 105 106 if (where <= PS_DLIST_UNKNOWN) { 107 /// XXX What is the better way to communicate this failure to the caller? 108 psError(__func__,"The given insert location (%i) for psDlistAdd is invalid. " 109 "Adding to head instead.",where); 110 where = PS_DLIST_HEAD; // given I can't tell caller about this, should just add it somewhere??? 111 } 112 113 if (where > list->size) { 114 psError(__FILE__, "Invalid index %d (only %d elements in psDList); assuming tail.", where, 115 list->size); 80 116 where = PS_DLIST_TAIL; 81 117 } 82 118 83 if (where == PS_DLIST_PREVIOUS) { 84 if (list->iter == NULL) { // if no iterator position, just insert it in the front of the list. 85 where = PS_DLIST_HEAD; 86 } else { 87 elem->prev = list->iter->prev; 88 elem->next = list->iter; 89 elem->data = psMemIncrRefCounter(data); 90 91 list->iter->prev = elem; 92 if (elem->prev != NULL) { 93 elem->prev->next = elem; 94 } 95 96 list->n++; 97 } 98 } 99 100 if (where == PS_DLIST_HEAD) { 101 elem->prev = NULL; 102 elem->next = list->head; 103 elem->data = psMemIncrRefCounter(data); 104 105 if (list->head != NULL) { 106 list->head->prev = elem; 107 } 108 109 list->head = elem; 110 if (list->tail == NULL) { 111 list->tail = elem; 112 } 113 list->n++; 114 } else if (where == PS_DLIST_TAIL) { 119 if (where == PS_DLIST_TAIL || list->size == 0) { 120 // insert the element at the end of the list 115 121 elem->prev = list->tail; 116 122 elem->next = NULL; 117 elem->data = psMemIncrRefCounter(data);118 123 119 124 if (list->tail != NULL) { … … 121 126 } 122 127 123 list->tail = elem;124 128 if (list->head == NULL) { 125 129 list->head = elem; 126 130 } 127 list->n++; 128 } else 129 else if (where == PS_DLIST_NEXT) { 130 if (list->iter == NULL) { 131 return psDlistAdd(list,data,PS_DLIST_TAIL); 132 } 133 elem->prev = list->iter; 134 elem->next = list->iter->next; 135 elem->data = psMemIncrRefCounter(data); 136 137 list->iter->next = elem; 138 if (elem->next != NULL) { 139 elem->next->prev = elem; 140 } 141 142 list->n++; 143 } else if (where < 0) { 144 /// XXX What is the best way to communicate this failure to the caller? 145 psError(__func__,"The given insert location (%i) for psDlistAdd is invalid. " 146 "Adding to head instead.",where); 147 return psDlistAdd(list,data,PS_DLIST_HEAD); // should add it somewhere... 148 } else {} 131 list->tail = elem; 132 133 list->size++; 134 list->iter = elem; 135 list->iterIndex = list->size - 1; 136 } else { 137 // move ourselves to the given position 138 dlistSetIterator(list, where, false); 139 position = dlistGetIterator(list); 140 141 if (position == NULL) { 142 psError(__func__,"%s failed to move cursor to specified location (%d)",__func__,where); 143 position = list->head; // since we no list->size != 0, this must be non-NULL 144 } 145 146 // insert our new element in front of the given position 147 elem->prev = position->prev; 148 elem->next = position; 149 position->prev = elem; 150 151 if (elem->prev == NULL) { // must be front of list 152 list->head = elem; 153 } else { 154 elem->prev->next = elem; 155 } 156 157 list->size++; 158 list->iter = elem; 159 } 160 161 elem->data = psMemIncrRefCounter(data); 162 163 pthread_mutex_unlock(&list->lock) 164 ; 149 165 150 166 return list; … … 153 169 /*****************************************************************************/ 154 170 155 psDlist *psDlistAppend(psDlist *list, // list to add to; may be NULL 156 void *data) // data to add at end 171 psDlist *psDlistAppend(psDlist *list, void *data) 157 172 { 158 173 return psDlistAdd(list, data, PS_DLIST_TAIL); … … 163 178 * Remove an element from a list 164 179 */ 165 void *psDlistRemove(psDlist *list, // list to remove element from 166 void *data, // data item to remove (or NULL) 167 int which) // index of item, if known. 168 // PS_DLIST_UNKNOWN, or PS_DLIST_HEAD, 169 // or PS_DLIST_TAIL 180 void *psDlistRemove(psDlist *list, void *data, int which) 170 181 { 171 182 psDlistElem *elem = NULL; // element to remove 172 assert (list != NULL); 173 174 if (data != NULL) 175 { 176 assert (which == PS_DLIST_UNKNOWN); 183 if (list == NULL) { 184 psError(__func__,"list parameter found to be NULL in %s",__func__); 185 return NULL; 186 } 187 188 // get exclusive access to list so that other threads will not get in the way. 189 pthread_mutex_lock(&list->lock) 190 ; 191 192 if (which == PS_DLIST_UNKNOWN) { 193 // search list for the data item. 177 194 178 195 int i = 0; // index 179 for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next , i++) {196 for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next) { 180 197 if (ptr->data == data) { 181 return psDlistRemove(list, NULL, i); 198 which = i; 199 break; 182 200 } 183 } 184 185 psTrace(__FILE__, 5, "Failed to find 0x%x on psDlist 0x%x", data, list); 186 201 i++; 202 } 203 204 if (which == PS_DLIST_UNKNOWN) { 205 psError(__func__, "Failed to find 0x%x on psDlist 0x%x in %s.", data, list,__func__); 206 return NULL; 207 } 208 } 209 210 // position the list's cursor to the desired location 211 dlistSetIterator(list,which,false); 212 elem = dlistGetIterator(list); 213 214 if (elem == NULL) { 215 psError(__func__, "Couldn't position to given index (%d) to remove element from list.",which); 187 216 return NULL; 188 217 } 189 218 190 if (which == PS_DLIST_HEAD || which == 0) 191 { 192 if (list->head == NULL) { 193 return NULL; 219 list->size--; 220 221 if (elem->prev == NULL) { // head of list? 222 list->head = elem->next; 223 } else { 224 elem->prev->next = elem->next; 225 } 226 227 if (elem->next == NULL) { // tail of list? 228 list->tail = elem->prev; 229 230 // removed tail, so iter should be the last element of list to keep it valid 231 if (list->size > 0) { 232 list->iter = list->tail; 233 list->iterIndex = list->size - 1; 194 234 } else { 195 elem = list->head; 196 197 if (list->head->next != NULL) { 198 list->head->next->prev = NULL; 199 } 200 list->head = list->head->next; 201 list->n--; 202 203 if (list->head == NULL) { 204 list->tail = NULL; 205 } 206 } 207 } else if (which == PS_DLIST_TAIL || which == list->n - 1) 208 { 209 if (list->tail == NULL) { 210 return NULL; 211 } else { 212 elem = list->tail; 213 if (list->tail->prev != NULL) { 214 list->tail->prev->next = NULL; 215 } 216 list->tail = list->tail->prev; 217 list->n--; 218 219 if (list->tail == NULL) { 220 list->head = NULL; 221 } 222 } 223 } else if (which != PS_DLIST_UNKNOWN) 224 { // an index in the middle of the list 225 assert (which != 0 && which != list->n - 1); 226 227 if (which < 0 || which >= list->n) { // out of bounds 228 psError(__func__,"Index %d is not in range [0..%d] for list 0x%x", which, list->n, 229 list); 230 return NULL; 231 } 232 233 int i = 0; // index 234 for (psDlistElem *ptr = list->head; ptr != NULL; ptr = ptr->next, i++) { 235 if (i == which) { 236 ptr->prev->next = ptr->next; 237 ptr->next->prev = ptr->prev; 238 239 elem = ptr; 240 } 241 } 242 } 235 list->iter = ITER_INIT_TAIL; 236 } 237 } else { 238 elem->next->prev = elem->prev; 239 list->iter = elem->next; 240 } 241 242 pthread_mutex_unlock(&list->lock) 243 ; 244 243 245 /* 244 246 * OK, delete list element and return the data 245 247 */ 246 assert (elem != NULL);247 248 data = elem->data; 248 249 dlistElemFree(elem); 249 250 250 return psMemDecrRefCounter(data); 251 251 } 252 252 253 /* 254 * Retrieve an element from the list, or iterate over list. 255 * 256 * If which is psDlist{Next,Prev} return the next/previous 257 * data and move the iteration cursor 258 * 259 * If which is psDlist{Head,Tail} initialize the iteration pointer 260 * and return the head/tail 261 * 262 * Otherwise, return the desired element 263 */ 264 #define ITER_INIT_HEAD ((void *)1) // next iteration should return head 265 #define ITER_INIT_TAIL ((void *)2) // next iteration should return tail 266 267 void *psDlistGet(const psDlist *list, int which) 268 { 253 void psDlistSetIterator(psDlist *list, int where) 254 { 255 dlistSetIterator(list,where,true); 256 } 257 258 void dlistSetIterator(psDlist* list, int where, bool lockList) 259 { 260 psDlistElem* cursor; 261 int position; 262 269 263 if (list == NULL) { 270 264 psError(__func__,"Unexpected null pointer for psDlist parameter (%s:%d).",__FILE__,__LINE__); 265 return; 266 } 267 268 if (where == PS_DLIST_CURRENT) { 269 return; 270 } 271 272 if (lockList) { 273 pthread_mutex_lock(&list->lock) 274 ; // don't want the list changing on us while we move about 275 } 276 277 if (where >= list->size) { 278 psError(__func__,"Tried to access an element beyond list end. " 279 "Moved to last element of list instead."); 280 where = list->size-1; 281 282 switch (where) { 283 case PS_DLIST_HEAD: 284 list->iter = ITER_INIT_HEAD; 285 break; 286 287 case PS_DLIST_TAIL: 288 list->iter = ITER_INIT_TAIL; 289 break; 290 291 case PS_DLIST_PREVIOUS: 292 cursor = dlistGetIterator(list); 293 position = dlistGetIteratorIndex(list); 294 295 if (cursor == NULL) { // list empty? 296 ((psDlist *)list)->iter = ITER_INIT_HEAD; 297 } else { 298 if (cursor->prev != NULL) { // don't go past head 299 list->iter = cursor->prev; 300 list->iterIndex = position-1; 301 break; 302 } 303 } 304 305 case PS_DLIST_NEXT: 306 cursor = dlistGetIterator(list); 307 position = dlistGetIteratorIndex(list); 308 309 if (cursor == NULL) { // list empty? 310 ((psDlist *)list)->iter = ITER_INIT_HEAD; 311 } else { 312 if (cursor->next != NULL) { // don't go pase tail 313 list->iter = cursor->next; 314 list->iterIndex = position+1; 315 break; 316 } 317 } 318 319 case PS_DLIST_UNKNOWN: 320 psError(__func__,"Can't move to the PS_DLIST_UNKNOWN position. Not moving the iterator position."); 321 break; 322 case PS_DLIST_CURRENT: 323 break; 324 325 default: 326 if (where < PS_DLIST_HEAD) { // bascially same as PS_DLIST_UNKNOWN above 327 psError(__func__,"Can't move to an unknown position. Not moving the iterator position."); 328 break; 329 } else { 330 int position = dlistGetIteratorIndex(list); 331 332 if (where < position) { 333 int diff = position-where; 334 for (int count=0;count < diff; count++) { 335 dlistSetIterator(list,PS_DLIST_PREVIOUS,false); 336 } 337 } else { 338 int diff = where-position; 339 for (int count=0;count < diff; count++) { 340 dlistSetIterator(list,PS_DLIST_NEXT,false); 341 } 342 } 343 } 344 break; 345 } 346 347 if (lockList) { 348 pthread_mutex_unlock(&list->lock) 349 ; 350 } 351 } 352 } 353 354 psDlistElem* dlistGetIterator(psDlist* list) 355 { 356 if (list->iter == ITER_INIT_HEAD) { 357 return list->head; 358 } else if (list->iter == ITER_INIT_TAIL) { 359 return list->tail; 360 } else { 361 return list->iter; 362 } 363 } 364 365 int dlistGetIteratorIndex(psDlist* list) 366 { 367 if (list->iter == ITER_INIT_HEAD) { 368 return 0; 369 } else if (list->iter == ITER_INIT_TAIL) { 370 return list->size-1; 371 } else { 372 return list->iterIndex; 373 } 374 } 375 376 void* psDlistGet(psDlist* list,int which) 377 { 378 psDlistElem* element; 379 380 psDlistSetIterator(list,which); 381 element = dlistGetIterator(list); 382 383 if (element == NULL) { 271 384 return NULL; 272 } 273 274 switch (which) { 275 case PS_DLIST_HEAD: 276 ((psDlist *)list)->iter = ITER_INIT_HEAD; 277 return (list->head == NULL) ? NULL : list->head->data; 278 279 case PS_DLIST_TAIL: 280 ((psDlist *)list)->iter = ITER_INIT_TAIL; 281 return (list->tail == NULL) ? NULL : list->tail->data; 282 283 case PS_DLIST_PREVIOUS: // use iterator 284 case PS_DLIST_NEXT: 285 if (list->iter == NULL) { 286 return NULL; 287 } else if (list->iter == ITER_INIT_HEAD) { 288 ((psDlist *)list)->iter = list->head; 289 } else if (list->iter == ITER_INIT_TAIL) { 290 ((psDlist *)list)->iter = list->tail; 291 } else if (which == PS_DLIST_PREVIOUS) { 292 ((psDlist *)list)->iter = list->iter->prev; 293 } else if (which == PS_DLIST_NEXT) { 294 ((psDlist *)list)->iter = list->iter->next; 295 } else { 296 psAbort(__func__,"Unreachable line was reached in %s:%d?",__FILE__,__LINE__); 297 } 298 299 if (list->iter == NULL) { 300 return NULL; 301 } 302 return list->iter->data; // XXX what if data is NULL? 303 304 break; 305 default: 306 if (which < 0) { 307 psError(__func__,"the position is invalid for %s",__func__); 308 return NULL; 309 } 310 ((psDlist *)list)->iter = list->head; 311 for (int i=0;i<which;i++) {} 312 313 if (list->iter == NULL) { 314 return NULL; 315 } 316 return list->iter->data; // XXX what if data is NULL? 317 } 318 } 319 320 psDlistElem* dlistGetIterator(psDlist* list) 321 { 322 323 324 /* 325 * Some wrappers for those iteration calls using psDlistGet. 326 * 327 * First a call to set the iteration pointer to the head of the list 328 */ 329 void psDlistSetIterator(psDlist *list, 330 int where) { 331 if (where != PS_DLIST_HEAD && where != PS_DLIST_TAIL) { 332 psError(__func__, "Invalid where argument: %d; assuming PS_DLIST_HEAD", where); 333 where = PS_DLIST_HEAD; 334 } 335 336 psDlistGet(list, where); // initialise iterator at head/tail 337 } 338 339 /* 340 * and now return the previous/next element of the list 341 */ 342 void *psDlistGetNext(psDlist *list) { 343 return psDlistGet(list, PS_DLIST_NEXT); 344 } 345 346 void *psDlistGetPrevious(psDlist *list) { 347 return psDlistGet(list, PS_DLIST_PREVIOUS); 348 } 349 350 void *psDlistGetCurrent(psDlist *list) { 351 return psDlistGet(list, PS_DLIST_CURRENT); 352 } 353 354 #if 0 355 /* 356 * Convert a psDlist to/from a psVoidPtrArray 357 */ 358 psVoidPtrArray *psDlistToArray(psDlist *restrict dlist) { 359 if (dlist == NULL) { 360 return NULL; 361 } 362 363 psVoidPtrArray *restrict arr = psVoidPtrArrayAlloc(dlist->n, dlist->n); 364 365 psDlistElem *ptr = dlist->head; 366 for (int i = 0, n = dlist->n; i < n; i++) { 367 arr->arr[i] = ptr->data; 368 369 ptr->data = NULL; 370 ptr = ptr->next; 371 } 372 373 psDlistFree(dlist, NULL); 374 375 return arr; 376 } 377 378 psDlist *psArrayToDlist(psVoidPtrArray *arr) { 379 psDlist *list = psDlistAlloc(NULL); // list of elements 380 381 for (int i = 0, n = arr->n; i < n; i++) { 382 psDlistAppend(list, 383 psMemDecrRefCounter(arr->arr[i])); // it's already Incr 384 arr->arr[i] = NULL; 385 } 386 387 psVoidPtrArrayFree(arr, NULL); 388 389 return list; 390 } 391 392 #endif 385 } else { 386 return element->data; 387 } 388 } 389 /* 390 * and now return the previous/next element of the list 391 */ 392 void *psDlistGetNext(psDlist *list) 393 { 394 return psDlistGet(list, PS_DLIST_NEXT); 395 } 396 397 void *psDlistGetPrevious(psDlist *list) 398 { 399 return psDlistGet(list, PS_DLIST_PREVIOUS); 400 } 401 402 void *psDlistGetCurrent(psDlist *list) 403 { 404 return psDlistGet(list, PS_DLIST_CURRENT); 405 } 406 407 #if 0 408 /* 409 * Convert a psDlist to/from a psVoidPtrArray 410 */ 411 psVoidPtrArray *psDlistToArray(psDlist *restrict dlist) 412 { 413 if (dlist == NULL) { 414 return NULL; 415 } 416 417 psVoidPtrArray *restrict arr = psVoidPtrArrayAlloc(dlist->size, dlist->size); 418 419 psDlistElem *ptr = dlist->head; 420 for (int i = 0, n = dlist->size; i < n; i++) { 421 arr->arr[i] = ptr->data; 422 423 ptr->data = NULL; 424 ptr = ptr->next; 425 } 426 427 psDlistFree(dlist, NULL); 428 429 return arr; 430 } 431 432 psDlist *psArrayToDlist(psVoidPtrArray *arr) 433 { 434 psDlist *list = psDlistAlloc(NULL); // list of elements 435 436 for (int i = 0, n = arr->size; i < n; i++) { 437 psDlistAppend(list, 438 psMemDecrRefCounter(arr->arr[i])); // it's already Incr 439 arr->arr[i] = NULL; 440 } 441 442 psVoidPtrArrayFree(arr, NULL); 443 444 return list; 445 } 446 447 #endif
Note:
See TracChangeset
for help on using the changeset viewer.
