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
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 }