00001
00002
00003
00004
00005 static const char rcsid[] =
00006 "$Id: hmap.c,v 1.18 2008/03/11 07:14:16 tho Exp $";
00007
00008 #include <stdlib.h>
00009 #include <unistd.h>
00010 #include <string.h>
00011 #include <stdio.h>
00012
00013 #include <toolbox/memory.h>
00014 #include <toolbox/carpal.h>
00015 #include <toolbox/hmap.h>
00016 #include <toolbox/misc.h>
00017
00023
00024 #define U_HMAP_MAX_SIZE 512
00025 #define U_HMAP_MAX_ELEMS U_HMAP_MAX_SIZE
00026 #define U_HMAP_RATE_FULL 0.75
00027 #define U_HMAP_RATE_RESIZE 3
00028
00029
00030
00031 struct u_hmap_q_s
00032 {
00033 void *key,
00034 *o;
00035
00036 TAILQ_ENTRY(u_hmap_q_s) next;
00037 };
00038
00039
00040 struct u_hmap_pcy_s
00041 {
00042 int (*pop)(u_hmap_t *hmap, u_hmap_o_t **obj);
00043 int (*push)(u_hmap_t *hmap, u_hmap_o_t *obj,
00044 u_hmap_q_t **data);
00045
00046 enum {
00047 U_HMAP_PCY_OP_PUT = 0x1,
00048 U_HMAP_PCY_OP_GET = 0x2
00049 } ops;
00050
00051 TAILQ_HEAD(u_hmap_q_h_s, u_hmap_q_s) queue;
00052 };
00053 typedef struct u_hmap_q_h_s u_hmap_q_h_t;
00054
00055
00056 struct u_hmap_s
00057 {
00058 u_hmap_opts_t *opts;
00059
00060 size_t sz,
00061 size,
00062 threshold,
00063 px;
00064
00065 u_hmap_pcy_t pcy;
00066
00067 LIST_HEAD(u_hmap_e_s, u_hmap_o_s) *hmap;
00068 };
00069 typedef struct u_hmap_e_s u_hmap_e_t;
00070
00071 static int _get (u_hmap_t *hmap, void *key,
00072 u_hmap_o_t **o);
00073
00074 static int _opts_check (u_hmap_opts_t *opts);
00075 static int _pcy_setup (u_hmap_t *hmap);
00076 static const char *_pcy2str(u_hmap_pcy_type_t policy);
00077
00078 static void _o_free (u_hmap_t *hmap, u_hmap_o_t *obj);
00079
00080 static u_hmap_q_t *_q_o_new (void *key);
00081 static void _q_o_free (u_hmap_q_t *s);
00082
00083 static size_t _f_hash (void *key, size_t size);
00084 static int _f_comp (void *k1, void *k2);
00085 static void _f_free (u_hmap_o_t *obj);
00086 static u_string_t *_f_str (u_hmap_o_t *obj);
00087
00088 static int _queue_push (u_hmap_t *hmap, u_hmap_o_t *obj,
00089 u_hmap_q_t **data);
00090 static int _queue_push_count (u_hmap_t *hmap, u_hmap_o_t *obj,
00091 u_hmap_q_t **counts);
00092 static int _queue_pop_front (u_hmap_t *hmap, u_hmap_o_t **obj);
00093 static int _queue_pop_back (u_hmap_t *hmap, u_hmap_o_t **obj);
00094
00095 static int _resize(u_hmap_t *hmap);
00096 static int _next_prime(size_t *prime, size_t sz, size_t *idx);
00097
00098
00106 const char *u_hmap_strerror (u_hmap_ret_t rc)
00107 {
00108 switch (rc)
00109 {
00110 case U_HMAP_ERR_NONE:
00111 return "success";
00112 case U_HMAP_ERR_FAIL:
00113 return "general failure";
00114 case U_HMAP_ERR_EXISTS:
00115 return "element already exists in table";
00116 }
00117 return NULL;
00118 }
00119
00120
00121 static size_t _f_hash (void *key, size_t size)
00122 {
00123 size_t h = 0;
00124 unsigned char *k = (unsigned char *) key;
00125
00126 dbg_ifb (key == NULL) return -1;
00127
00128 while (*k)
00129 {
00130 h += *k++;
00131 h += (h << 10);
00132 h ^= (h >> 6);
00133 }
00134
00135 h += (h << 3);
00136 h ^= (h >> 11);
00137
00138 return (h + (h << 15)) % size;
00139 }
00140
00141
00142 static int _f_comp (void *k1, void *k2)
00143 {
00144 dbg_ifb (k1 == NULL) return -1;
00145 dbg_ifb (k2 == NULL) return -1;
00146
00147 return strcmp((char *)k1, (char *)k2);
00148 }
00149
00150
00151 static void _f_free (u_hmap_o_t *obj)
00152 {
00153 dbg_ifb (obj == NULL) return;
00154
00155 u_free(obj->key);
00156 u_free(obj->val);
00157 }
00158
00159
00160 static u_string_t *_f_str (u_hmap_o_t *obj)
00161 {
00162 enum { MAX_OBJ_STR = 256 };
00163 char buf[MAX_OBJ_STR];
00164 u_string_t *s = NULL;
00165 char *key,
00166 *val;
00167
00168 dbg_err_if (obj == NULL);
00169
00170 key = (char *) obj->key,
00171 val = (char *) obj->val;
00172
00173 dbg_err_if (u_snprintf(buf, MAX_OBJ_STR, "[%s:%s]", key, val));
00174 dbg_err_if (u_string_create(buf, strlen(buf)+1, &s));
00175
00176 return s;
00177
00178 err:
00179 return NULL;
00180 }
00181
00182
00183 static int _opts_check (u_hmap_opts_t *opts)
00184 {
00185 dbg_err_if (opts == NULL);
00186
00187 dbg_err_if (opts->size == 0);
00188 dbg_err_if (opts->max == 0);
00189 dbg_err_if (opts->type != U_HMAP_TYPE_CHAIN &&
00190 opts->type != U_HMAP_TYPE_LINEAR);
00191 dbg_err_if (opts->policy < U_HMAP_PCY_NONE ||
00192 opts->policy > U_HMAP_PCY_LFU);
00193 dbg_err_if (opts->f_hash == NULL);
00194 dbg_err_if (opts->f_comp == NULL);
00195
00196 return U_HMAP_ERR_NONE;
00197
00198 err:
00199 return U_HMAP_ERR_FAIL;
00200 }
00201
00202
00203 static int _pcy_setup (u_hmap_t *hmap)
00204 {
00205 dbg_return_if (hmap == NULL, ~0);
00206
00207 switch (hmap->opts->policy)
00208 {
00209 case U_HMAP_PCY_NONE:
00210 hmap->pcy.push = NULL;
00211 hmap->pcy.pop = NULL;
00212 hmap->pcy.ops = 0;
00213 break;
00214 case U_HMAP_PCY_LRU:
00215 hmap->pcy.push = _queue_push;
00216 hmap->pcy.pop = _queue_pop_back;
00217 hmap->pcy.ops = U_HMAP_PCY_OP_PUT | U_HMAP_PCY_OP_GET;
00218 break;
00219 case U_HMAP_PCY_FIFO:
00220 hmap->pcy.push = _queue_push;
00221 hmap->pcy.pop = _queue_pop_back;
00222 hmap->pcy.ops = U_HMAP_PCY_OP_PUT;
00223 break;
00224 case U_HMAP_PCY_LFU:
00225 hmap->pcy.push = _queue_push_count;
00226 hmap->pcy.pop = _queue_pop_front;
00227 hmap->pcy.ops = U_HMAP_PCY_OP_PUT | U_HMAP_PCY_OP_GET;
00228 break;
00229 default:
00230 dbg("Invalid policy: %d", hmap->opts->policy);
00231 return U_HMAP_ERR_FAIL;
00232 }
00233
00234 return U_HMAP_ERR_NONE;
00235 }
00236
00249 int u_hmap_new (u_hmap_opts_t *opts, u_hmap_t **hmap)
00250 {
00251 size_t i;
00252 u_hmap_t *c = NULL;
00253
00254
00255 dbg_return_if (hmap == NULL, ~0);
00256
00257 dbg_return_sif ((c = (u_hmap_t *) u_zalloc(sizeof(u_hmap_t))) == NULL, ~0);
00258
00259 dbg_err_if (u_hmap_opts_new(&c->opts));
00260 if (opts)
00261 {
00262 dbg_err_if (u_hmap_opts_copy(c->opts, opts));
00263 dbg_err_if (_opts_check(c->opts));
00264 }
00265 u_hmap_opts_dbg(c->opts);
00266 dbg_err_if (_pcy_setup(c));
00267
00268 c->size = c->opts->size;
00269 dbg_err_if (_next_prime(&c->size, c->size, &c->px));
00270 c->threshold = U_HMAP_RATE_FULL * c->size;
00271
00272 dbg_err_sif ((c->hmap = (u_hmap_e_t *)
00273 u_zalloc(sizeof(u_hmap_e_t) *
00274 c->size)) == NULL);
00275
00276
00277 for (i = 0; i < c->size; ++i)
00278 LIST_INIT(&c->hmap[i]);
00279
00280 TAILQ_INIT(&c->pcy.queue);
00281
00282 dbg("[hmap]");
00283 dbg("threshold: %u", c->threshold);
00284
00285 *hmap = c;
00286
00287 return U_HMAP_ERR_NONE;
00288
00289 err:
00290 u_free(c);
00291 *hmap = NULL;
00292 return U_HMAP_ERR_FAIL;
00293 }
00294
00306 int u_hmap_copy (u_hmap_t *to, u_hmap_t *from)
00307 {
00308 u_hmap_o_t *obj;
00309 size_t i;
00310
00311 dbg_err_if (to == NULL);
00312 dbg_err_if (from == NULL);
00313
00314 for (i = 0; i < from->size; ++i)
00315 {
00316 while ((obj = LIST_FIRST(&from->hmap[i])) != NULL)
00317 {
00318 LIST_REMOVE(obj, next);
00319 dbg_err_if (u_hmap_put(to, obj, NULL));
00320 }
00321 }
00322
00323 return U_HMAP_ERR_NONE;
00324
00325 err:
00326 return U_HMAP_ERR_FAIL;
00327 }
00328
00336 void u_hmap_dbg (u_hmap_t *hmap)
00337 {
00338 enum { MAX_LINE = 255 };
00339 u_string_t *s = NULL, *st = NULL;
00340 u_hmap_o_t *obj;
00341 size_t i;
00342
00343 dbg_ifb (hmap == NULL) return;
00344
00345 dbg ("<hmap>");
00346 for (i = 0; i < hmap->size; ++i)
00347 {
00348 dbg_ifb (u_string_create("", 1, &s)) return;
00349 dbg_err_if (u_string_clear(s));
00350 dbg_err_if (u_string_append(s, "|", 1));
00351
00352 LIST_FOREACH(obj, &hmap->hmap[i], next)
00353 {
00354 if (hmap->opts->f_str == NULL)
00355 {
00356 dbg_err_if (u_string_append(s, "[]", 2));
00357 } else {
00358 st = hmap->opts->f_str(obj);
00359 dbg_err_if (u_string_append(s, u_string_c(st),
00360 u_string_len(st)-1));
00361 u_string_free(st);
00362 }
00363 }
00364 dbg_err_if (u_string_append(s, "|", 1));
00365 dbg(u_string_c(s));
00366 dbg_ifb (u_string_free(s)) return;
00367 }
00368 dbg("</hmap>");
00369 return;
00370
00371 err:
00372 U_FREEF(st, u_string_free);
00373 U_FREEF(s, u_string_free);
00374 return;
00375 }
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389 int u_hmap_del (u_hmap_t *hmap, void *key, u_hmap_o_t **obj)
00390 {
00391 u_hmap_o_t *o = NULL;
00392
00393 dbg_err_if (hmap == NULL);
00394 dbg_err_if (key == NULL);
00395
00396 if (obj)
00397 *obj = NULL;
00398
00399 if (_get(hmap, key, &o))
00400 return U_HMAP_ERR_FAIL;
00401
00402 dbg_err_if (o == NULL);
00403 LIST_REMOVE(o, next);
00404
00405 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
00406 _o_free(hmap, o);
00407 else
00408 if (obj)
00409 *obj = o;
00410
00411 hmap->sz--;
00412
00413 return U_HMAP_ERR_NONE;
00414
00415 err:
00416 return U_HMAP_ERR_FAIL;
00417 }
00418
00419
00420 static int _get (u_hmap_t *hmap, void *key,
00421 u_hmap_o_t **o)
00422 {
00423 u_hmap_o_t *obj;
00424 u_hmap_e_t *x;
00425 int comp;
00426 size_t hash;
00427
00428 dbg_err_if (hmap == NULL);
00429 dbg_err_if (key == NULL);
00430 dbg_err_if (o == NULL);
00431
00432 hash = hmap->opts->f_hash(key, hmap->size);
00433
00434 if (hmap->opts->f_hash != &_f_hash &&
00435 !(hmap->opts->options & U_HMAP_OPTS_HASH_STRONG)) {
00436 enum { MAX_INT = 20 };
00437 char h[MAX_INT];
00438
00439 u_snprintf(h, MAX_INT, "%u", hash);
00440 hash = _f_hash(h, hmap->size);
00441 }
00442
00443 x = &hmap->hmap[hash];
00444
00445 switch (hmap->opts->type)
00446 {
00447 case U_HMAP_TYPE_CHAIN:
00448
00449 LIST_FOREACH(obj, x, next)
00450 {
00451 if ((comp = hmap->opts->f_comp(key, obj->key)) == 0)
00452 {
00453 *o = obj;
00454 return U_HMAP_ERR_NONE;
00455 } else if (comp < 0) {
00456 *o = NULL;
00457 break;
00458 }
00459 }
00460 break;
00461
00462
00463 case U_HMAP_TYPE_LINEAR:
00464 {
00465 size_t last = ((hash + hmap->size -1) % hmap->size);
00466
00467 for (; hash != last; hash = ((hash +1) % hmap->size),
00468 x = &hmap->hmap[hash])
00469 {
00470 if (!LIST_EMPTY(x))
00471 {
00472 obj = LIST_FIRST(x);
00473
00474 if ((hmap->opts->f_comp(key, obj->key)) == 0)
00475 {
00476 *o = obj;
00477 return U_HMAP_ERR_NONE;
00478 }
00479 }
00480 }
00481 }
00482
00483 break;
00484 }
00485
00486 err:
00487 return U_HMAP_ERR_FAIL;
00488 }
00489
00497 void u_hmap_pcy_dbg (u_hmap_t *hmap)
00498 {
00499 u_hmap_q_t *data;
00500 u_string_t *s = NULL;
00501
00502 dbg_ifb (hmap == NULL) return;
00503
00504 dbg_ifb (u_string_create("", 1, &s)) return;
00505 dbg_err_if (u_string_clear(s));
00506 dbg_err_if (u_string_append(s, "Policy: [", strlen("Policy: [")));
00507
00508 TAILQ_FOREACH(data, &hmap->pcy.queue, next)
00509 {
00510 dbg_err_if (u_string_append(s, "(", 1));
00511 dbg_err_if (u_string_append(s, data->key, strlen(data->key)));
00512 dbg_err_if (u_string_append(s, ")", 1));
00513 }
00514 dbg_err_if (u_string_append(s, "]", 1));
00515 dbg(u_string_c(s));
00516 dbg_if (u_string_free(s));
00517
00518 return;
00519
00520 err:
00521 U_FREEF(s, u_string_free);
00522 return;
00523 }
00524
00525
00526 static int _queue_pop_front (u_hmap_t *hmap, u_hmap_o_t **obj)
00527 {
00528 u_hmap_q_t *first;
00529
00530 dbg_err_if (hmap == NULL);
00531
00532 dbg_err_if ((first = TAILQ_FIRST(&hmap->pcy.queue)) == NULL);
00533 dbg_err_if (u_hmap_del(hmap, first->key, obj));
00534 TAILQ_REMOVE(&hmap->pcy.queue, first, next);
00535 _q_o_free(first);
00536
00537 return U_HMAP_ERR_NONE;
00538
00539 err:
00540 return U_HMAP_ERR_FAIL;
00541 }
00542
00543
00544 static int _queue_pop_back (u_hmap_t *hmap, u_hmap_o_t **obj)
00545 {
00546 u_hmap_q_t *last;
00547
00548 dbg_err_if (hmap == NULL);
00549
00550 dbg_err_if ((last = TAILQ_LAST(&hmap->pcy.queue, u_hmap_q_h_s))
00551 == NULL);
00552 dbg_err_if (u_hmap_del(hmap, last->key, obj));
00553 TAILQ_REMOVE(&hmap->pcy.queue, last, next);
00554 _q_o_free(last);
00555
00556 return U_HMAP_ERR_NONE;
00557
00558 err:
00559 return U_HMAP_ERR_FAIL;
00560 }
00561
00562
00563 static int _queue_push (u_hmap_t *hmap, u_hmap_o_t *obj,
00564 u_hmap_q_t **data)
00565 {
00566 u_hmap_q_t *new;
00567
00568 dbg_err_if (hmap == NULL);
00569 dbg_err_if (obj == NULL);
00570 dbg_err_if (data == NULL);
00571
00572 if (*data == NULL)
00573 {
00574 dbg_err_if ((new = _q_o_new(obj->key)) == NULL);
00575 TAILQ_INSERT_HEAD(&hmap->pcy.queue, new, next);
00576 *data = new;
00577 } else {
00578 TAILQ_REMOVE(&hmap->pcy.queue, *data, next);
00579 TAILQ_INSERT_HEAD(&hmap->pcy.queue, *data, next);
00580 }
00581 return U_HMAP_ERR_NONE;
00582
00583 err:
00584 return U_HMAP_ERR_FAIL;
00585 }
00586
00587
00588 static int _queue_push_count (u_hmap_t *hmap, u_hmap_o_t *obj,
00589 u_hmap_q_t **counts)
00590 {
00591 u_hmap_q_t *new, *t;
00592 int *count;
00593
00594 dbg_err_if (hmap == NULL);
00595 dbg_err_if (obj == NULL);
00596 dbg_err_if (counts == NULL);
00597
00598 if (*counts == NULL)
00599 {
00600 dbg_err_if ((new = _q_o_new(obj->key)) == NULL);
00601 TAILQ_INSERT_HEAD(&hmap->pcy.queue, new, next);
00602 *counts = TAILQ_FIRST(&hmap->pcy.queue);
00603 dbg_err_sif ((count = (int *) u_zalloc(sizeof(int))) == NULL);
00604 new->o = (void *) count;
00605 *counts = new;
00606 } else {
00607 count = (int *) (*counts)->o;
00608 memset((void *) count, (*count)++, sizeof(int));
00609
00610 if ((t = TAILQ_NEXT(*counts, next)))
00611 {
00612 for (; t && ((*count) > *((int *) t->o)); t = TAILQ_NEXT(t, next))
00613 ;
00614 TAILQ_REMOVE(&hmap->pcy.queue, *counts, next);
00615 if (t)
00616 TAILQ_INSERT_BEFORE(t, *counts, next);
00617 else
00618 TAILQ_INSERT_TAIL(&hmap->pcy.queue, *counts, next);
00619 }
00620 }
00621 return U_HMAP_ERR_NONE;
00622
00623 err:
00624 return U_HMAP_ERR_FAIL;
00625 }
00626
00641 int u_hmap_put (u_hmap_t *hmap, u_hmap_o_t *obj, u_hmap_o_t **old)
00642 {
00643 u_hmap_o_t *o;
00644 u_hmap_e_t *x;
00645 int comp;
00646 size_t hash;
00647
00648 dbg_err_if (hmap == NULL);
00649 dbg_err_if (obj == NULL);
00650
00651 if (old)
00652 *old = NULL;
00653
00654 if (hmap->sz >= hmap->threshold) {
00655 dbg("hmap full");
00656 if (hmap->opts->policy == U_HMAP_PCY_NONE) {
00657 dbg_err_if (_resize(hmap));
00658 } else {
00659 dbg("freeing according to policy %d", hmap->opts->policy);
00660 dbg_err_if (hmap->pcy.pop(hmap, old));
00661 }
00662 }
00663
00664 hash = hmap->opts->f_hash(obj->key, hmap->size);
00665
00666 if (hmap->opts->f_hash != &_f_hash &&
00667 !(hmap->opts->options & U_HMAP_OPTS_HASH_STRONG)) {
00668 enum { MAX_INT = 20 };
00669 char h[MAX_INT];
00670
00671 u_snprintf(h, MAX_INT, "%u", hash);
00672 hash = _f_hash(h, hmap->size);
00673 }
00674
00675 if (hmap->opts->policy != U_HMAP_PCY_NONE &&
00676 hmap->sz >= hmap->opts->max)
00677 {
00678 dbg("Cache full - freeing according to policy %d", hmap->opts->policy);
00679 hmap->pcy.pop(hmap, old);
00680 }
00681
00682 x = &hmap->hmap[hash];
00683
00684 switch (hmap->opts->type)
00685 {
00686 case U_HMAP_TYPE_CHAIN:
00687
00688 if (LIST_EMPTY(x))
00689 {
00690 LIST_INSERT_HEAD(x, obj, next);
00691 goto end;
00692 } else {
00693 LIST_FOREACH(o, x, next)
00694 {
00695
00696 if ((comp = hmap->opts->f_comp(obj->key, o->key)) == 0)
00697 {
00698
00699 if (!(hmap->opts->options & U_HMAP_OPTS_NO_OVERWRITE))
00700 {
00701 LIST_INSERT_AFTER(o, obj, next);
00702 LIST_REMOVE(o, next);
00703 hmap->sz--;
00704
00705
00706 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
00707 _o_free(hmap, o);
00708 else
00709 if (old)
00710 *old = o;
00711
00712 goto end;
00713
00714
00715 } else {
00716
00717 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
00718 _o_free(hmap, obj);
00719 else
00720 if (old)
00721 *old = obj;
00722
00723 return U_HMAP_ERR_EXISTS;
00724 }
00725 } else {
00726 if (comp < 0)
00727 {
00728 LIST_INSERT_BEFORE(o, obj, next);
00729 goto end;
00730 } else if (!LIST_NEXT(o, next)) {
00731 LIST_INSERT_AFTER(o, obj, next);
00732 goto end;
00733 }
00734 }
00735 }
00736 }
00737 break;
00738
00739 case U_HMAP_TYPE_LINEAR:
00740
00741 {
00742 size_t last = ((hash + hmap->size -1) % hmap->size);
00743
00744 for (; hash != last; hash = ((hash+1) % hmap->size),
00745 x = &hmap->hmap[hash])
00746 {
00747 if (LIST_EMPTY(x))
00748 {
00749 LIST_INSERT_HEAD(x, obj, next);
00750 goto end;
00751
00752 } else {
00753
00754 o = LIST_FIRST(x);
00755
00756
00757 if (hmap->opts->f_comp(o->key, obj->key) == 0)
00758 {
00759
00760 if (!(hmap->opts->options & U_HMAP_OPTS_NO_OVERWRITE))
00761 {
00762 LIST_INSERT_AFTER(o, obj, next);
00763 LIST_REMOVE(o, next);
00764 hmap->sz--;
00765
00766
00767 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
00768 _o_free(hmap, obj);
00769 else
00770 if (old)
00771 *old = obj;
00772
00773 goto end;
00774
00775
00776 } else {
00777
00778 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
00779 _o_free(hmap, obj);
00780 else
00781 if (old)
00782 *old = obj;
00783
00784 return U_HMAP_ERR_EXISTS;
00785 }
00786 }
00787 }
00788 }
00789 }
00790 break;
00791 }
00792
00793 err:
00794 return U_HMAP_ERR_FAIL;
00795
00796 end:
00797 hmap->sz++;
00798
00799 if (hmap->pcy.ops & U_HMAP_PCY_OP_PUT)
00800 hmap->pcy.push(hmap, obj, &obj->pqe);
00801
00802 return U_HMAP_ERR_NONE;
00803 }
00804
00818 int u_hmap_get (u_hmap_t *hmap, void *key, u_hmap_o_t **obj)
00819 {
00820 dbg_err_if (hmap == NULL);
00821 dbg_err_if (key == NULL);
00822 dbg_err_if (obj == NULL);
00823
00824 if (_get(hmap, key, obj))
00825 {
00826 *obj = NULL;
00827 return U_HMAP_ERR_FAIL;
00828 }
00829 dbg_err_if (obj == NULL);
00830
00831 if (hmap->pcy.ops & U_HMAP_PCY_OP_GET)
00832 hmap->pcy.push(hmap, *obj, &(*obj)->pqe);
00833
00834 return U_HMAP_ERR_NONE;
00835
00836 err:
00837 return U_HMAP_ERR_FAIL;
00838 }
00839
00851 int u_hmap_foreach (u_hmap_t *hmap, int f(void *val))
00852 {
00853 u_hmap_o_t *obj;
00854 size_t i;
00855
00856 dbg_err_if (hmap == NULL);
00857 dbg_err_if (f == NULL);
00858
00859 for (i = 0; i < hmap->size; ++i)
00860 {
00861 LIST_FOREACH(obj, &hmap->hmap[i], next)
00862 dbg_err_if (f(obj->val));
00863 }
00864
00865 return U_HMAP_ERR_NONE;
00866
00867 err:
00868 return U_HMAP_ERR_FAIL;
00869 }
00870
00882 int u_hmap_foreach_keyval(u_hmap_t *hmap, int f(void *key, void *val))
00883 {
00884 struct u_hmap_o_s *obj;
00885 size_t i;
00886
00887 dbg_err_if (hmap == NULL);
00888 dbg_err_if (f == NULL);
00889
00890 for (i = 0; i < hmap->size; ++i)
00891 {
00892 LIST_FOREACH(obj, &hmap->hmap[i], next)
00893 dbg_err_if (f(obj->key,obj->val));
00894 }
00895
00896 return U_HMAP_ERR_NONE;
00897 err:
00898 return U_HMAP_ERR_FAIL;
00899 }
00900
00901
00911 void u_hmap_free (u_hmap_t *hmap)
00912 {
00913 u_hmap_o_t *obj;
00914 u_hmap_q_t *data;
00915 size_t i;
00916
00917 dbg_ifb (hmap == NULL) return;
00918
00919
00920 for (i = 0; i < hmap->size; ++i)
00921 {
00922 while ((obj = LIST_FIRST(&hmap->hmap[i])) != NULL)
00923 {
00924 LIST_REMOVE(obj, next);
00925 _o_free(hmap, obj);
00926 }
00927 }
00928
00929 u_free(hmap->hmap);
00930
00931
00932 while ((data = TAILQ_FIRST(&hmap->pcy.queue)) != NULL)
00933 {
00934 TAILQ_REMOVE(&hmap->pcy.queue, data, next);
00935 _q_o_free(data);
00936 }
00937
00938 u_free(hmap->opts);
00939 u_free(hmap);
00940
00941 return;
00942 }
00943
00955 int u_hmap_opts_new (u_hmap_opts_t **opts)
00956 {
00957 u_hmap_opts_t *o;
00958
00959 dbg_err_if (opts == NULL);
00960
00961 dbg_err_sif ((o = (u_hmap_opts_t *) u_zalloc(sizeof(u_hmap_opts_t)))
00962 == NULL);
00963
00964 u_hmap_opts_init(o);
00965
00966 *opts = o;
00967
00968 return U_HMAP_ERR_NONE;
00969 err:
00970 *opts = NULL;
00971 return U_HMAP_ERR_FAIL;
00972 }
00973
00984 int u_hmap_opts_copy (u_hmap_opts_t *to, u_hmap_opts_t *from)
00985 {
00986 dbg_err_if (to == NULL);
00987 dbg_err_if (from == NULL);
00988
00989 memcpy(to, from, sizeof(u_hmap_opts_t));
00990
00991 return U_HMAP_ERR_NONE;
00992
00993 err:
00994 return U_HMAP_ERR_FAIL;
00995 }
00996
01004 void u_hmap_opts_init (u_hmap_opts_t *opts)
01005 {
01006 dbg_ifb (opts == NULL) return;
01007
01008 opts->size = U_HMAP_MAX_SIZE;
01009 opts->type = U_HMAP_TYPE_CHAIN;
01010 opts->max = U_HMAP_MAX_ELEMS;
01011 opts->policy = U_HMAP_PCY_NONE;
01012 opts->options = 0;
01013 opts->f_hash = &_f_hash;
01014 opts->f_comp = &_f_comp;
01015 opts->f_free = &_f_free;
01016 opts->f_str = &_f_str;
01017
01018 return;
01019 }
01020
01028 void u_hmap_opts_free (u_hmap_opts_t *opts)
01029 {
01030 dbg_ifb (opts == NULL) return;
01031
01032 u_free(opts);
01033 }
01034
01042 void u_hmap_opts_dbg (u_hmap_opts_t *opts)
01043 {
01044 dbg_ifb (opts == NULL) return;
01045
01046 dbg("[hmap options]");
01047 dbg("size: %u", opts->size);
01048 dbg("max: %u", opts->max);
01049 dbg("policy: %s", _pcy2str(opts->policy));
01050 dbg("ownsdata: %d, &f_free: %x",
01051 (opts->options & U_HMAP_OPTS_OWNSDATA)>0,
01052 &opts->f_free);
01053 dbg("no_overwrite: %d", (opts->options & U_HMAP_OPTS_NO_OVERWRITE)>0);
01054 }
01055
01068 u_hmap_o_t *u_hmap_o_new (void *key, void *val)
01069 {
01070 u_hmap_o_t *obj = NULL;
01071
01072 dbg_return_if (key == NULL, NULL);
01073 dbg_return_if (val == NULL, NULL);
01074
01075 dbg_err_sif ((obj = (u_hmap_o_t *)
01076 u_zalloc(sizeof(u_hmap_o_t))) == NULL);
01077
01078 obj->key = key;
01079 obj->val = val;
01080 obj->pqe = NULL;
01081
01082 return obj;
01083
01084 err:
01085 u_free(obj);
01086 return NULL;
01087 }
01088
01100 void u_hmap_o_free (u_hmap_o_t *obj)
01101 {
01102 dbg_ifb (obj == NULL) return;
01103
01104 u_free(obj);
01105 }
01106
01107
01108 static void _o_free (u_hmap_t *hmap, u_hmap_o_t *obj)
01109 {
01110 dbg_ifb (hmap == NULL) return;
01111 dbg_ifb (obj == NULL) return;
01112
01113 if (hmap->opts->options & U_HMAP_OPTS_OWNSDATA)
01114 {
01115 if (hmap->opts->f_free)
01116 hmap->opts->f_free(obj);
01117
01118 u_hmap_o_free(obj);
01119 }
01120 }
01121
01122
01123 static u_hmap_q_t *_q_o_new (void *key)
01124 {
01125 u_hmap_q_t *data = NULL;
01126
01127 dbg_return_if (key == NULL, NULL);
01128
01129 dbg_err_sif ((data = (u_hmap_q_t *)
01130 u_zalloc(sizeof(u_hmap_q_t))) == NULL);
01131
01132 data->key = key;
01133 data->o = NULL;
01134
01135 return data;
01136
01137 err:
01138 u_free(data);
01139 return NULL;
01140 }
01141
01142
01143 static void _q_o_free (u_hmap_q_t *data)
01144 {
01145 dbg_ifb (data == NULL) return;
01146
01147 u_free(data->o);
01148 u_free(data);
01149 }
01150
01151
01152 static const char *_pcy2str (u_hmap_pcy_type_t policy)
01153 {
01154 switch (policy)
01155 {
01156 case U_HMAP_PCY_NONE:
01157 return "none";
01158 case U_HMAP_PCY_FIFO:
01159 return "fifo";
01160 case U_HMAP_PCY_LRU:
01161 return "fifo";
01162 case U_HMAP_PCY_LFU:
01163 return "lfu";
01164 }
01165 return NULL;
01166 }
01167
01168 static int _next_prime(size_t *prime, size_t sz, size_t *idx)
01169 {
01170 static size_t primes[] = {
01171 13, 19, 29, 41, 59, 79, 107, 149, 197, 263, 347, 457, 599, 787, 1031,
01172 1361, 1777, 2333, 3037, 3967, 5167, 6719, 8737, 11369, 14783, 19219,
01173 24989, 32491, 42257, 54941, 71429, 92861, 120721, 156941, 204047,
01174 265271, 344857, 448321, 582821, 757693, 985003, 1280519, 1664681,
01175 2164111, 2813353, 3657361, 4754591, 6180989, 8035301, 10445899,
01176 13579681, 17653589, 22949669, 29834603, 38784989, 50420551, 65546729,
01177 85210757, 110774011, 144006217, 187208107, 243370577, 316381771,
01178 411296309, 534685237, 695090819, 903618083, 1174703521, 1527114613,
01179 1837299131, 2147483647
01180 };
01181
01182 size_t i;
01183
01184 dbg_err_if (prime == NULL);
01185 dbg_err_if (sz == 0);
01186 dbg_err_if (idx == NULL);
01187
01188 for (i = *idx; i < sizeof(primes)/sizeof(size_t); ++i) {
01189 if (primes[i] >= sz) {
01190 *idx = i;
01191 *prime = primes[i];
01192 goto ok;
01193 }
01194 }
01195 dbg_err_ifm (1, "hmap size limit exceeded");
01196
01197 ok:
01198 return 0;
01199
01200 err:
01201 return ~0;
01202 }
01203
01204 static int _resize(u_hmap_t *hmap)
01205 {
01206 u_hmap_opts_t *newopts = NULL;
01207 u_hmap_t *newmap = NULL;
01208
01209 dbg_err_if (hmap == NULL);
01210
01211 if (hmap->opts->policy != U_HMAP_PCY_NONE)
01212 return 0;
01213
01214 dbg("resize from: %u", hmap->size);
01215
01216
01217 dbg_err_if (u_hmap_opts_new(&newopts));
01218 dbg_err_if (u_hmap_opts_copy(newopts, hmap->opts));
01219
01220
01221 dbg_err_if (_next_prime(&newopts->size,
01222 U_HMAP_RATE_RESIZE * newopts->size,
01223 &hmap->px));
01224 dbg_err_if (u_hmap_new(newopts, &newmap));
01225 u_hmap_opts_free(newopts);
01226
01227
01228 hmap->opts->options &= !U_HMAP_OPTS_OWNSDATA;
01229
01230
01231 dbg_err_if (u_hmap_copy(newmap, hmap));
01232
01233
01234 u_hmap_opts_free(hmap->opts);
01235 u_free(hmap->hmap);
01236
01237
01238 memcpy(hmap, newmap, sizeof(u_hmap_t));
01239 u_free(newmap);
01240
01241 dbg("resized to: %u", hmap->size);
01242
01243 return 0;
01244
01245 err:
01246 return ~0;
01247 }
01248