Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

linklist.c

00001 #include "linklist.h"
00002 #include "dbug_mem.h"
00003 
00004 
00005 //
00006 // public methods
00007 //
00008 
00009 
00010 void
00011 list_init(List *list, int (*match)(const void *key1, const void *key2), 
00012    void (*destroy)(void *data))
00013 {
00014    //MSG_DEBUG("list_init() called");
00015    
00016    T_RDWR_INIT(&(list->rwlock), NULL);
00017    
00018    // Initialize the list.
00019    list->size = 0;
00020    
00021    if (destroy != NULL) {
00022       list->destroy = destroy;
00023    } else {
00024       list->destroy = stringFreeFunction;
00025    }
00026    
00027    if (match != NULL) {
00028       list->match = match;
00029    } else {
00030       list->match = stringMatchFunction;
00031    }
00032    
00033    list->head = NULL;
00034    list->tail = NULL;
00035 }
00036 
00037 
00038 void
00039 list_destroy(List *list)
00040 {
00041    void *data = NULL;
00042    
00043    //MSG_DEBUG("list_destroy() called");
00044    
00045    T_RDWR_WLOCK(&(list->rwlock));
00046    
00047    // Remove each element.
00048    while (list_size(list) > 0) {
00049       if (list_rem_next(list, NULL, (void **)&data) == 0 && 
00050             list->destroy != NULL) {
00051          // Call a user-defined function to free dynamically allocated data.
00052          list->destroy(data);
00053       }
00054    }
00055    
00056    // No operations are allowed now, but clear the structure as a precaution.
00057     memset(list, 0, sizeof(List));
00058    
00059     T_RDWR_WUNLOCK(&(list->rwlock));
00060    
00061    return;
00062 }
00063 
00064 
00065 int
00066 list_getsize(List *list)
00067 {
00068    int retval = 0;
00069    
00070    //MSG_DEBUG("list_getsize() called");
00071    
00072    T_RDWR_RLOCK(&(list->rwlock));
00073    
00074    retval = list_size(list);
00075    
00076    T_RDWR_RUNLOCK(&(list->rwlock));
00077    
00078    return retval;
00079 }
00080 
00081 
00082 int
00083 list_insert(List *list, void *data)
00084 {
00085    int retval = -1;
00086    void *temp = data;
00087    
00088    //MSG_DEBUG("list_insert() called");
00089    
00090    T_RDWR_WLOCK(&(list->rwlock));
00091    
00092    // check if already there
00093    if(list_internal_lookup(list, &temp)==0) {
00094       // element already there
00095       retval = 1;
00096    } else {
00097       // create element in list
00098       retval = list_ins_next(list, NULL, data);
00099    }
00100    
00101    T_RDWR_WUNLOCK(&(list->rwlock));
00102    
00103    return retval;
00104 }
00105 
00106 
00107 int
00108 list_lookup(List *list, void **data)
00109 {
00110    int retval = -1;
00111    
00112    //MSG_DEBUG("list_lookup() called");
00113    
00114    T_RDWR_RLOCK(&(list->rwlock));
00115    
00116    retval = list_internal_lookup(list, data);
00117    
00118    T_RDWR_RUNLOCK(&(list->rwlock));
00119    
00120    return retval;
00121 }
00122 
00123 
00124 int
00125 list_for_each_call(List *list, int (*func)(void *data, void *userdata), 
00126    void *userdata)
00127 {
00128    ListElmt *element;
00129    int retval = 0;
00130    void *data=NULL;
00131    
00132    //MSG_DEBUG("list_for_each_call() called");
00133    
00134    T_RDWR_RLOCK(&(list->rwlock));
00135    
00136    // Search for the data in list.
00137    for (element = list_head(list); element != NULL && retval==0; element = 
00138          list_next(element)) {
00139       data = (void *)element->data;
00140       retval = func(data, userdata);
00141    }
00142    
00143    T_RDWR_RUNLOCK(&(list->rwlock));
00144    
00145    return retval;
00146 }
00147 
00148 
00149 int
00150 list_remove_each_if_func_eq_1(List *list, int (*func)(void *data, void *userdata), 
00151    void *userdata)
00152 {
00153    ListElmt *element, *prev, *next;
00154    void *data = NULL;
00155    
00156    //MSG_DEBUG("list_remove_each_if_func_eq_1(): called");
00157    
00158    T_RDWR_WLOCK(&(list->rwlock));
00159    
00160    // Search for the data in list.
00161    prev = NULL;
00162    
00163    for (element = list_head(list); element != NULL;) {
00164       next = list_next(element);
00165       if (func(list_data(element), userdata) == 1) {
00166          // Remove the data from list.
00167          if (list_rem_next(list, prev, &data) == 0 &&
00168                list->destroy != NULL) {
00169             // Call a user-defined function to free dynamically allocated data.
00170             list->destroy(data);
00171          }
00172       } else {
00173          prev = element;
00174       }
00175       element = next;
00176    }
00177    
00178    T_RDWR_WUNLOCK(&(list->rwlock));
00179    
00180    return 0;
00181 }
00182 
00183 int
00184 list_foreach_match(List *list, int (*matchfunc)(const void *key1, const void *key2), void (*callbackfunc)(const void *data), void **data)
00185 {
00186    ListElmt *element;
00187     int retval = -1;
00188    
00189    //MSG_DEBUG("list_remove_each_if_func_eq_1(): called");
00190    
00191    T_RDWR_RLOCK(&(list->rwlock));
00192    
00193    
00194    for (element = list_head(list); element != NULL ; element = list_next(element)) {
00195       if (matchfunc(*data, list_data(element))) {
00196          callbackfunc(list_data(element));
00197             retval = 0;
00198       }
00199    }
00200    
00201    T_RDWR_RUNLOCK(&(list->rwlock));
00202    
00203    return retval;
00204 }
00205 
00206 
00207 int
00208 list_remove(List *list, void **data)
00209 {
00210    ListElmt *element, *prev;
00211    
00212    //MSG_DEBUG("list_remove() called");
00213    
00214    T_RDWR_WLOCK(&(list->rwlock));
00215    
00216    // Search for the data in list.
00217    prev = NULL;
00218    
00219    for (element = list_head(list); element != NULL; element = 
00220          list_next(element)) {
00221       if (list->match(*data, list_data(element))) {
00222          // Remove the data from list.
00223          if (list_rem_next(list, prev, data) == 0) {
00224             T_RDWR_WUNLOCK(&(list->rwlock));
00225             return 0;
00226          } else {
00227             T_RDWR_WUNLOCK(&(list->rwlock));
00228             return -1;
00229          }
00230         }
00231       prev = element;
00232    }
00233    
00234    T_RDWR_WUNLOCK(&(list->rwlock));
00235    
00236    // Return that the data was not found.
00237    return -1;
00238 }
00239 
00240 
00241 //
00242 // private methods
00243 //
00244 
00245 
00246 // INTERNAL => NOT PROTECTED AGAINST THREADING ==> DO NOT USE FROM OUTSIDE
00247 int
00248 list_ins_next(List *list, ListElmt *element, const void *data)
00249 {
00250    ListElmt *new_element = NULL;
00251    
00252    //MSG_DEBUG("list_ins_next() called");
00253    
00254    // Allocate storage for the element.
00255    if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL) {
00256       return -1;
00257    }
00258    
00259    // Insert the element into the list.
00260    new_element->data = (void *)data;
00261    
00262    if (element == NULL) {
00263       // Handle insertion at the head of the list.
00264       if (list_size(list) == 0) {
00265          list->tail = new_element;
00266       }
00267       
00268       new_element->next = list->head;
00269       list->head = new_element;
00270    } else {
00271       // Handle insertion somewhere other than at the head.
00272       if (element->next == NULL) {
00273          list->tail = new_element;
00274       }
00275    
00276       new_element->next = element->next;
00277       element->next = new_element;
00278    }
00279    
00280    // Adjust the size of the list to account for the inserted element.
00281    list->size++;
00282    
00283    return 0;
00284 }
00285 
00286 
00287 // INTERNAL => NOT PROTECTED AGAINST THREADING ==> DO NOT USE FROM OUTSIDE
00288 int
00289 list_rem_next(List *list, ListElmt *element, void **data)
00290 {
00291    ListElmt *old_element = NULL;
00292    
00293    //MSG_DEBUG("list_rem_next() called");
00294    
00295    // Do not allow removal from an empty list.
00296    if (list_size(list) == 0) {
00297       return -1;
00298    }
00299    
00300    // Remove the element from the list.
00301    if (element == NULL) {
00302       // Handle removal from the head of the list.
00303       *data = list->head->data;
00304       old_element = list->head;
00305       list->head = list->head->next;
00306       
00307       if (list_size(list) == 1) {
00308          list->tail = NULL;
00309       }
00310    } else {
00311       // Handle removal from somewhere other than the head.
00312       if (element->next == NULL) {
00313          return -1;
00314       }
00315       
00316       *data = element->next->data;
00317       old_element = element->next;
00318       element->next = element->next->next;
00319       
00320       if (element->next == NULL) {
00321          list->tail = element;
00322       }
00323    }
00324    
00325    // Free the storage allocated by the abstract data type.
00326    free(old_element);
00327    
00328    // Adjust the size of the list to account for the removed element.
00329    list->size--;
00330    
00331     return 0;
00332 }
00333 
00334 
00335 // INTERNAL => NOT PROTECTED AGAINST THREADING ==> DO NOT USE FROM OUTSIDE
00336 int
00337 stringMatchFunction(const void *key1, const void *key2)
00338 {
00339    int res = 0;
00340    
00341    res = strcmp(key1, key2);
00342    
00343    return res == 0 ? 1 : 0;
00344 }
00345 
00346 
00347 // INTERNAL => NOT PROTECTED AGAINST THREADING ==> DO NOT USE FROM OUTSIDE
00348 void
00349 stringFreeFunction(void *ptr)
00350 {
00351    if (ptr != NULL) free(ptr);
00352 }
00353 
00354 
00355 // INTERNAL => NOT PROTECTED AGAINST THREADING ==> DO NOT USE FROM OUTSIDE
00356 int
00357 list_internal_lookup(List *list, void **data)
00358 {
00359    ListElmt *element;
00360    int retval = -1;
00361    
00362    //MSG_DEBUG("list_internal_lookup() called");
00363    
00364    // Search for the data in the bucket.
00365    for (element = list_head(list); element != NULL && retval!=0; element =
00366          list_next(element)) {
00367       if (list->match(*data, list_data(element))) {
00368          // Pass back the data from the table.
00369          *data = list_data(element);
00370          retval = 0;
00371       }
00372    }
00373    
00374    // Return that the data was not found.
00375    return retval;
00376 }

Generated on Wed Mar 30 13:43:26 2005 for Mntd by  doxygen 1.3.9.1