00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00039 #include "debug.h"
00040 #include "result.h"
00041 #include "util.h"
00042 #include "chhash.h"
00043
00044 typedef struct m_chhash_bucket_list_s m_chhash_bucket_list_t;
00045
00046 struct m_chhash_bucket_s {
00047 struct m_chhash_bucket_s *next;
00048 struct m_chhash_bucket_s *prev;
00049 m_chhash_key_t key;
00050 m_chhash_value_t value;
00051 };
00052
00053 struct m_chhash_bucket_list_s {
00054 m_mutex_t mutex;
00055 m_chhash_bucket_t *head;
00056 m_chhash_bucket_t *free;
00057 };
00058
00059 struct m_chhash_s {
00060 unsigned int tbl_size;
00061 m_chhash_bucket_list_t *tbl;
00062 bool mtsafe;
00063 };
00064
00065
00066 m_result_t
00067 m_chhash_create(m_chhash_t** hp, unsigned int table_size, bool mtsafe)
00068 {
00069 int i;
00070
00071 *hp = (m_chhash_t *) MALLOC(sizeof(m_chhash_t));
00072 if (*hp == NULL)
00073 {
00074 return M_R_NOMEMORY;
00075 }
00076 (*hp)->tbl = (m_chhash_bucket_list_t*) CALLOC (table_size,
00077 sizeof(m_chhash_bucket_list_t));
00078 if ((*hp)->tbl == NULL)
00079 {
00080 FREE(*hp);
00081 return M_R_NOMEMORY;
00082 }
00083
00084 for (i=0; i<table_size; i++)
00085 {
00086 M_MUTEX_INIT(&(*hp)->tbl[i].mutex, NULL);
00087 (*hp)->tbl[i].head = NULL;
00088 (*hp)->tbl[i].free = NULL;
00089 }
00090 (*hp)->tbl_size = table_size;
00091 (*hp)->mtsafe = mtsafe;
00092
00093 return M_R_SUCCESS;
00094 }
00095
00096
00097 m_result_t
00098 m_chhash_destroy(m_chhash_t** hp)
00099 {
00100 m_chhash_bucket_t *bucket;
00101 m_chhash_bucket_t *next_bucket;
00102 int i;
00103
00104 if (*hp == NULL)
00105 {
00106 return M_R_SUCCESS;
00107 }
00108 for (i=0; i<(*hp)->tbl_size; i++) {
00109 for (bucket = (*hp)->tbl[i].head; bucket; bucket = next_bucket) {
00110 next_bucket = bucket->next;
00111 FREE(bucket);
00112 }
00113 for (bucket = (*hp)->tbl[i].free; bucket; bucket = next_bucket) {
00114 next_bucket = bucket->next;
00115 FREE(bucket);
00116 }
00117 }
00118
00119 FREE((*hp)->tbl);
00120 FREE(*hp);
00121
00122 return M_R_SUCCESS;
00123 }
00124
00125
00126 static void
00127 bucket_list_add(m_chhash_bucket_t **head, m_chhash_bucket_t *bucket)
00128 {
00129 if (*head)
00130 {
00131 (*head)->prev = bucket;
00132 }
00133 bucket->next = *head;
00134 bucket->prev = NULL;
00135 (*head) = bucket;
00136 }
00137
00138
00139 static void
00140 bucket_list_remove(m_chhash_bucket_t **head, m_chhash_bucket_t *bucket)
00141 {
00142 if (*head == bucket)
00143 {
00144 *head = bucket->next;
00145 bucket->prev = NULL;
00146 } else {
00147 bucket->prev->next = bucket->next;
00148 if (bucket->next)
00149 {
00150 bucket->next->prev = bucket->prev;
00151 }
00152 }
00153 }
00154
00155
00156 m_result_t
00157 m_chhash_add(m_chhash_t* h,
00158 m_chhash_key_t key,
00159 m_chhash_value_t value)
00160 {
00161 m_result_t result;
00162 m_chhash_bucket_t *bucket;
00163 m_chhash_bucket_list_t *bucket_list = &h->tbl[key % h->tbl_size];
00164
00165 if (h->mtsafe == true)
00166 {
00167 M_MUTEX_LOCK(&(bucket_list->mutex));
00168 }
00169
00170 for (bucket = bucket_list->head;
00171 bucket != NULL;
00172 bucket = bucket->next)
00173 {
00174 if (bucket->key == key)
00175 {
00176 result = M_R_EXISTS;
00177 goto done;
00178 }
00179 }
00180 if (bucket_list->free)
00181 {
00182 bucket = bucket_list->free;
00183 bucket_list_remove(&bucket_list->free, bucket);
00184 } else {
00185 bucket = (m_chhash_bucket_t *) MALLOC(sizeof(m_chhash_bucket_t));
00186 }
00187 bucket->key = key;
00188 bucket->value = value;
00189 bucket_list_add(&bucket_list->head, bucket);
00190 result = M_R_SUCCESS;
00191
00192 done:
00193 if (h->mtsafe == true)
00194 {
00195 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00196 }
00197 return result;
00198 }
00199
00200
00201 m_result_t
00202 m_chhash_lookup(m_chhash_t* h,
00203 m_chhash_key_t key,
00204 m_chhash_value_t *value)
00205 {
00206 m_result_t result;
00207 m_chhash_bucket_t *bucket;
00208 m_chhash_bucket_list_t *bucket_list;
00209
00210 bucket_list = &h->tbl[key % h->tbl_size];
00211
00212 if (h->mtsafe == true)
00213 {
00214 M_MUTEX_LOCK(&(bucket_list->mutex));
00215 }
00216
00217 for (bucket = bucket_list->head;
00218 bucket != NULL;
00219 bucket = bucket->next)
00220 {
00221 if (bucket->key == key)
00222 {
00223 if (value)
00224 {
00225 *value = bucket->value;
00226 }
00227 result = M_R_SUCCESS;
00228 goto done;
00229 }
00230 }
00231 result = M_R_NOTEXISTS;
00232
00233 done:
00234 if (h->mtsafe == true)
00235 {
00236 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00237 }
00238 return result;
00239
00240 }
00241
00242
00243 m_result_t
00244 m_chhash_remove(m_chhash_t* h,
00245 m_chhash_key_t key,
00246 m_chhash_value_t *value)
00247 {
00248 m_result_t result;
00249 m_chhash_bucket_t *bucket;
00250 m_chhash_bucket_list_t *bucket_list;
00251
00252 bucket_list = &h->tbl[key % h->tbl_size];
00253
00254 if (h->mtsafe == true)
00255 {
00256 M_MUTEX_LOCK(&(bucket_list->mutex));
00257 }
00258
00259 for (bucket = bucket_list->head;
00260 bucket != NULL;
00261 bucket = bucket->next)
00262 {
00263 if (bucket->key == key)
00264 {
00265 if (value)
00266 {
00267 *value = bucket->value;
00268 }
00269 bucket_list_remove(&bucket_list->head, bucket);
00270 bucket_list_add(&bucket_list->free, bucket);
00271 result = M_R_SUCCESS;
00272 goto done;
00273 }
00274 }
00275 result = M_R_NOTEXISTS;
00276 done:
00277 if (h->mtsafe == true)
00278 {
00279 M_MUTEX_UNLOCK(&(bucket_list->mutex));
00280 }
00281 return result;
00282 }
00283
00284
00285
00286 void
00287 m_chhash_iter_init(m_chhash_t *chhash, m_chhash_iter_t *iter)
00288 {
00289 unsigned int i;
00290 m_chhash_bucket_t *bucket;
00291
00292 iter->chhash = chhash;
00293 iter->index = 0;
00294 iter->bucket = NULL;
00295
00296 for (i=0; i<chhash->tbl_size; i++) {
00297 if (bucket = chhash->tbl[i].head) {
00298 iter->bucket = bucket;
00299 iter->index = i;
00300 break;
00301 }
00302 }
00303 }
00304
00305
00306 m_result_t
00307 m_chhash_iter_next(m_chhash_iter_t *iter,
00308 m_chhash_key_t *key,
00309 m_chhash_value_t *value)
00310 {
00311 unsigned int i;
00312 m_chhash_bucket_t *bucket;
00313 m_chhash_t *chhash = iter->chhash;
00314
00315 if (iter->bucket == NULL) {
00316 *key = 0;
00317 *value = NULL;
00318 return M_R_NULLITER;
00319 }
00320
00321 *key = iter->bucket->key;
00322 *value = iter->bucket->value;
00323
00324 if (iter->bucket->next) {
00325 iter->bucket = iter->bucket->next;
00326 } else {
00327 iter->bucket = NULL;
00328 for (i=iter->index+1; i<chhash->tbl_size; i++) {
00329 if (bucket = chhash->tbl[i].head) {
00330 iter->bucket = bucket;
00331 iter->index = i;
00332 break;
00333 }
00334 }
00335 }
00336 return M_R_SUCCESS;
00337
00338 }
00339
00340
00341 void
00342 m_chhash_print(m_chhash_t *h) {
00343 int i;
00344 m_chhash_bucket_list_t *bucket_list;
00345 m_chhash_bucket_t *bucket;
00346
00347 fprintf(M_DEBUG_OUT, "HASH TABLE: %p\n", h);
00348 for (i=0;i<h->tbl_size; i++)
00349 {
00350 bucket_list = &h->tbl[i];
00351 if (bucket = bucket_list->head) {
00352 fprintf(M_DEBUG_OUT, "[%d]: head", i);
00353 for (; bucket != NULL; bucket=bucket->next)
00354 {
00355 fprintf(M_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00356 }
00357 fprintf(M_DEBUG_OUT, "\n");
00358 }
00359 if (bucket = bucket_list->free) {
00360 fprintf(M_DEBUG_OUT, "[%d]: free", i);
00361 for (; bucket != NULL; bucket=bucket->next)
00362 {
00363 fprintf(M_DEBUG_OUT, " --> (%u, %p)", bucket->key, bucket->value);
00364 }
00365 fprintf(M_DEBUG_OUT, "\n");
00366 }
00367 }
00368 }