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