src/misc/hash_table.c

Go to the documentation of this file.
00001 
00007 #include <misc/result.h>
00008 #include <misc/malloc.h>
00009 #include <misc/hash_table.h>
00010 #include <misc/debug.h>
00011 #include <misc/mutex.h>
00012 #include <pthread.h>
00013 
00014 typedef struct txc_hash_table_bucket_list_s txc_hash_table_bucket_list_t;
00015 
00016 struct txc_hash_table_bucket_s {
00017         struct txc_hash_table_bucket_s *next;
00018         struct txc_hash_table_bucket_s *prev;
00019         txc_hash_table_key_t           key;
00020         txc_hash_table_value_t         value;
00021 };
00022 
00023 struct txc_hash_table_bucket_list_s {
00024         txc_mutex_t             mutex;
00025         txc_hash_table_bucket_t *head;
00026         txc_hash_table_bucket_t *free;
00027 };
00028 
00029 struct txc_hash_table_s {
00030         unsigned int                 tbl_size;
00031         txc_hash_table_bucket_list_t *tbl;
00032         txc_bool_t                   mtsafe;
00033 };
00034 
00035 
00036 txc_result_t 
00037 txc_hash_table_create(txc_hash_table_t** hp, unsigned int table_size, txc_bool_t mtsafe)
00038 {
00039         int i;
00040 
00041         *hp = (txc_hash_table_t *) MALLOC(sizeof(txc_hash_table_t));
00042         if (*hp == NULL) 
00043         {
00044                 return TXC_R_NOMEMORY;
00045         }
00046         (*hp)->tbl = (txc_hash_table_bucket_list_t*) CALLOC (table_size,
00047                                                        sizeof(txc_hash_table_bucket_list_t));
00048         if ((*hp)->tbl == NULL) 
00049         {
00050                 FREE(*hp);
00051                 return TXC_R_NOMEMORY;
00052         }
00053 
00054         for (i=0; i<table_size; i++) 
00055         {
00056                 TXC_MUTEX_INIT(&(*hp)->tbl[i].mutex, NULL);
00057                 (*hp)->tbl[i].head = NULL;
00058                 (*hp)->tbl[i].free = NULL;
00059         }
00060         (*hp)->tbl_size = table_size;
00061         (*hp)->mtsafe = mtsafe;
00062 
00063         return TXC_R_SUCCESS;
00064 }
00065 
00066 
00067 txc_result_t
00068 txc_hash_table_destroy(txc_hash_table_t** hp)
00069 {
00070         txc_hash_table_bucket_t *bucket;
00071         txc_hash_table_bucket_t *next_bucket;
00072         int               i;
00073 
00074         if (*hp == NULL) 
00075         {
00076                 return TXC_R_SUCCESS;
00077         }
00078         for (i=0; i<(*hp)->tbl_size; i++) {
00079                 for (bucket = (*hp)->tbl[i].head; bucket; bucket = next_bucket) {
00080                         next_bucket = bucket->next;
00081                         FREE(bucket);
00082                 }
00083                 for (bucket = (*hp)->tbl[i].free; bucket; bucket = next_bucket) {
00084                         next_bucket = bucket->next;
00085                         FREE(bucket);
00086                 }
00087         }
00088 
00089         FREE((*hp)->tbl);
00090         FREE(*hp);
00091         
00092         return TXC_R_SUCCESS;
00093 }
00094 
00095 
00096 static void 
00097 bucket_list_add(txc_hash_table_bucket_t **head, txc_hash_table_bucket_t *bucket)
00098 {
00099         if (*head)
00100         {
00101                 (*head)->prev = bucket;
00102         }
00103         bucket->next = *head;
00104         bucket->prev = NULL;
00105         (*head) = bucket;
00106 }
00107 
00108 
00109 static void 
00110 bucket_list_remove(txc_hash_table_bucket_t **head, txc_hash_table_bucket_t *bucket)
00111 {
00112         if (*head == bucket) 
00113         {
00114                 *head = bucket->next;
00115                 bucket->prev = NULL;
00116         } else {
00117                 bucket->prev->next = bucket->next;
00118                 if (bucket->next) 
00119                 {
00120                         bucket->next->prev = bucket->prev;
00121                 }       
00122         }       
00123 }
00124 
00125 
00126 txc_result_t
00127 txc_hash_table_add(txc_hash_table_t* h, 
00128                    txc_hash_table_key_t key, 
00129                    txc_hash_table_value_t value)
00130 {
00131         txc_result_t                 result;
00132         txc_hash_table_bucket_t      *bucket;
00133         txc_hash_table_bucket_list_t *bucket_list = &h->tbl[key % h->tbl_size];
00134 
00135         if (h->mtsafe == TXC_BOOL_TRUE) 
00136         {
00137                 TXC_MUTEX_LOCK(&(bucket_list->mutex));
00138         }
00139 
00140         for (bucket = bucket_list->head; 
00141              bucket != NULL; 
00142              bucket = bucket->next) 
00143         {
00144                 if (bucket->key == key) 
00145                 {
00146                         result = TXC_R_EXISTS;
00147                         goto done;
00148                 }
00149         }
00150         if (bucket_list->free) 
00151         {
00152                 bucket = bucket_list->free;
00153                 bucket_list_remove(&bucket_list->free, bucket);
00154         } else {
00155                 bucket = (txc_hash_table_bucket_t *) MALLOC(sizeof(txc_hash_table_bucket_t));
00156         }       
00157         bucket->key = key;
00158         bucket->value = value;
00159         bucket_list_add(&bucket_list->head, bucket);
00160         result = TXC_R_SUCCESS;
00161 
00162 done:
00163         if (h->mtsafe == TXC_BOOL_TRUE) 
00164         {
00165                 TXC_MUTEX_UNLOCK(&(bucket_list->mutex));
00166         }
00167         return result;
00168 }
00169 
00170 
00171 txc_result_t
00172 txc_hash_table_lookup(txc_hash_table_t* h,
00173                       txc_hash_table_key_t key, 
00174                       txc_hash_table_value_t *value)
00175 {
00176         txc_result_t                 result;
00177         txc_hash_table_bucket_t      *bucket;
00178         txc_hash_table_bucket_list_t *bucket_list;
00179 
00180         bucket_list = &h->tbl[key % h->tbl_size];
00181 
00182         if (h->mtsafe == TXC_BOOL_TRUE) 
00183         {
00184                 TXC_MUTEX_LOCK(&(bucket_list->mutex));
00185         }
00186 
00187         for (bucket = bucket_list->head; 
00188              bucket != NULL; 
00189              bucket = bucket->next) 
00190         {
00191                 if (bucket->key == key) 
00192                 {
00193                         if (value) 
00194                         {
00195                                 *value = bucket->value; 
00196                         }       
00197                         result = TXC_R_SUCCESS;
00198                         goto done;
00199                 }
00200         }
00201         result = TXC_R_NOTEXISTS;
00202 
00203 done:
00204         if (h->mtsafe == TXC_BOOL_TRUE) 
00205         {
00206                 TXC_MUTEX_UNLOCK(&(bucket_list->mutex));
00207         }
00208         return result;
00209 
00210 }
00211 
00212 
00213 txc_result_t
00214 txc_hash_table_remove(txc_hash_table_t* h,
00215                       txc_hash_table_key_t key, 
00216                       txc_hash_table_value_t *value)
00217 {
00218         txc_result_t                 result;
00219         txc_hash_table_bucket_t      *bucket;
00220         txc_hash_table_bucket_list_t *bucket_list;
00221 
00222         bucket_list = &h->tbl[key % h->tbl_size];
00223 
00224         if (h->mtsafe == TXC_BOOL_TRUE) 
00225         {
00226                 TXC_MUTEX_LOCK(&(bucket_list->mutex));
00227         }
00228 
00229         for (bucket = bucket_list->head; 
00230              bucket != NULL; 
00231              bucket = bucket->next) 
00232         {
00233                 if (bucket->key == key) 
00234                 {
00235                         if (value) 
00236                         {
00237                                 *value = bucket->value; 
00238                         }       
00239                         bucket_list_remove(&bucket_list->head, bucket);
00240                         bucket_list_add(&bucket_list->free, bucket);
00241                         result = TXC_R_SUCCESS;
00242                         goto done;
00243                 }
00244         }
00245         result = TXC_R_NOTEXISTS;
00246 done:
00247         if (h->mtsafe == TXC_BOOL_TRUE) 
00248         {
00249                 TXC_MUTEX_UNLOCK(&(bucket_list->mutex));
00250         }
00251         return result;
00252 }
00253 
00254 /* Iterator is not multithreaded safe */
00255 
00256 void
00257 txc_hash_table_iter_init(txc_hash_table_t *hash_table, txc_hash_table_iter_t *iter)
00258 {
00259         unsigned int            i;
00260         txc_hash_table_bucket_t *bucket;
00261 
00262         iter->hash_table = hash_table;
00263         iter->index = 0;
00264         iter->bucket = NULL;
00265 
00266         for (i=0; i<hash_table->tbl_size; i++) {
00267                 if (bucket = hash_table->tbl[i].head) {
00268                         iter->bucket = bucket;
00269                         iter->index = i;
00270                         break;
00271                 }
00272         }
00273 }
00274 
00275 
00276 txc_result_t
00277 txc_hash_table_iter_next(txc_hash_table_iter_t *iter, 
00278                          txc_hash_table_key_t *key, 
00279                          txc_hash_table_value_t *value)
00280 {
00281         unsigned int            i;
00282         txc_hash_table_bucket_t *bucket;
00283         txc_hash_table_t        *hash_table = iter->hash_table;
00284 
00285         if (iter->bucket == NULL) {
00286                 *key = 0;
00287                 *value = NULL;
00288                 return TXC_R_NULLITER;
00289         } 
00290 
00291         *key = iter->bucket->key;
00292         *value = iter->bucket->value;
00293 
00294         if (iter->bucket->next) {
00295                 iter->bucket = iter->bucket->next;
00296         } else {        
00297                 iter->bucket = NULL;
00298                 for (i=iter->index+1; i<hash_table->tbl_size; i++) {
00299                         if (bucket = hash_table->tbl[i].head) {
00300                                 iter->bucket = bucket;
00301                                 iter->index = i;
00302                                 break;
00303                         }
00304                 }
00305         }
00306         return TXC_R_SUCCESS;
00307 
00308 }
00309 
00310 
00311 void 
00312 txc_hash_table_print(txc_hash_table_t *h) {
00313         int i;
00314         txc_hash_table_bucket_list_t *bucket_list;
00315         txc_hash_table_bucket_t      *bucket;
00316 
00317         fprintf(TXC_DEBUG_OUT, "HASH TABLE: %p\n", h);
00318         for (i=0;i<h->tbl_size; i++)
00319         {
00320                 bucket_list = &h->tbl[i];
00321                 if (bucket = bucket_list->head) {
00322                         fprintf(TXC_DEBUG_OUT, "[%d]: head", i);
00323                         for (; bucket != NULL; bucket=bucket->next)
00324                         {
00325                                 fprintf(TXC_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00326                         }
00327                         fprintf(TXC_DEBUG_OUT, "\n");
00328                 }
00329                 if (bucket = bucket_list->free) {
00330                         fprintf(TXC_DEBUG_OUT, "[%d]: free", i);
00331                         for (; bucket != NULL; bucket=bucket->next)
00332                         {
00333                                 fprintf(TXC_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00334                         }
00335                         fprintf(TXC_DEBUG_OUT, "\n");
00336                 }
00337         }
00338 }

Generated on Wed Dec 9 20:32:39 2009 for xCalls by  doxygen 1.4.7