00001
00002
00003 #include <sys/types.h>
00004 #include <stdlib.h>
00005 #include <unistd.h>
00006 #include <string.h>
00007 #include <stdio.h>
00008
00009 #include <toolbox/memory.h>
00010 #include <toolbox/carpal.h>
00011 #include <toolbox/queue.h>
00012 #include <toolbox/str.h>
00013 #include <toolbox/hmap.h>
00014
00020
00021 #define U_HMAP_MAX_SIZE 512
00022 #define U_HMAP_MAX_ELEMS U_HMAP_MAX_SIZE
00023
00024
00025
00026 struct u_hmap_queue_o_s
00027 {
00028 char *key;
00029 void *o;
00030 TAILQ_ENTRY(u_hmap_queue_o_s) next;
00031 };
00032
00033
00034 struct u_hmap_o_s
00035 {
00036 char *key;
00037 void *val;
00038 LIST_ENTRY(u_hmap_o_s) next;
00039 struct u_hmap_queue_o_s *pqe;
00040 };
00041
00042
00043 struct u_hmap_pcy_s
00044 {
00045 int (*pop)(struct u_hmap_s *hmap);
00046 int (*push)(struct u_hmap_s *hmap, struct u_hmap_o_s *obj,
00047 struct u_hmap_queue_o_s **data);
00048 TAILQ_HEAD(u_hmap_queue_h_s, u_hmap_queue_o_s) queue;
00049 enum {
00050 U_HMAP_PCY_OP_PUT = 0x1,
00051 U_HMAP_PCY_OP_GET = 0x2
00052 } ops;
00053 };
00054
00055
00056 struct u_hmap_s
00057 {
00058 u_hmap_opts_t *opts;
00059 size_t size;
00060 LIST_HEAD(u_hmap_e_s, u_hmap_o_s) *hmap;
00061 struct u_hmap_pcy_s pcy;
00062 };
00063
00064
00065 static int _get (u_hmap_t *hmap, const char *key,
00066 struct u_hmap_o_s **o);
00067
00068 static int _opts_check (u_hmap_opts_t *opts);
00069 static int _pcy_setup (u_hmap_t *hmap);
00070
00071 static struct u_hmap_o_s *_o_new (const char *key, void *val);
00072 static void _o_free (u_hmap_t *hmap, struct u_hmap_o_s *obj);
00073
00074 static struct u_hmap_queue_o_s *_data_o_new(const char *key);
00075 static void _data_o_free (struct u_hmap_queue_o_s *s);
00076
00077 static size_t _f_hash (const char *key, size_t size);
00078 static int _f_comp (const char *k1, const char *k2);
00079 static void _f_free (void *val);
00080
00081 static int _queue_push (u_hmap_t *hmap, struct u_hmap_o_s *obj,
00082 struct u_hmap_queue_o_s **data);
00083 static int _queue_push_count (u_hmap_t *hmap, struct u_hmap_o_s *obj,
00084 struct u_hmap_queue_o_s **counts);
00085 static int _queue_pop_front (u_hmap_t *hmap);
00086 static int _queue_pop_back (u_hmap_t *hmap);
00087
00088
00089 static size_t _f_hash (const char *key, size_t size)
00090 {
00091 size_t h = 0;
00092
00093 while (*key)
00094 {
00095 h += *key++;
00096 h += (h << 10);
00097 h ^= (h >> 6);
00098 }
00099
00100 h += (h << 3);
00101 h ^= (h >> 11);
00102
00103 return (h + (h << 15)) % size;
00104 }
00105
00106 static int _f_comp (const char *k1, const char *k2)
00107 {
00108 return strcmp(k1, k2);
00109 }
00110
00111 static void _f_free (void *val)
00112 {
00113 dbg_ifb (val == NULL) return;
00114
00115 u_free(val);
00116 }
00117
00118 static int _opts_check (u_hmap_opts_t *opts)
00119 {
00120 dbg_err_if (opts == NULL);
00121
00122 dbg_err_if (opts->max_size == 0);
00123 dbg_err_if (opts->max_elems == 0);
00124 dbg_err_if (opts->policy < U_HMAP_PCY_NONE ||
00125 opts->policy > U_HMAP_PCY_LFU);
00126 dbg_err_if (opts->f_hash == NULL);
00127 dbg_err_if (opts->f_comp == NULL);
00128 dbg_err_if (opts->f_free == NULL);
00129
00130 return 0;
00131
00132 err:
00133 return ~0;
00134 }
00135
00136 static int _pcy_setup (u_hmap_t *hmap)
00137 {
00138 dbg_return_if (hmap == NULL, ~0);
00139
00140 switch (hmap->opts->policy)
00141 {
00142 case U_HMAP_PCY_NONE:
00143 hmap->pcy.push = NULL;
00144 hmap->pcy.pop = NULL;
00145 hmap->pcy.ops = 0;
00146 break;
00147 case U_HMAP_PCY_LRU:
00148 hmap->pcy.push = _queue_push;
00149 hmap->pcy.pop = _queue_pop_back;
00150 hmap->pcy.ops = U_HMAP_PCY_OP_PUT | U_HMAP_PCY_OP_GET;
00151 break;
00152 case U_HMAP_PCY_FIFO:
00153 hmap->pcy.push = _queue_push;
00154 hmap->pcy.pop = _queue_pop_back;
00155 hmap->pcy.ops = U_HMAP_PCY_OP_PUT;
00156 break;
00157 case U_HMAP_PCY_LFU:
00158 hmap->pcy.push = _queue_push_count;
00159 hmap->pcy.pop = _queue_pop_front;
00160 hmap->pcy.ops = U_HMAP_PCY_OP_PUT | U_HMAP_PCY_OP_GET;
00161 break;
00162 default:
00163 dbg("Invalid policy: %d", hmap->opts->policy);
00164 return ~0;
00165 }
00166 return 0;
00167 }
00168
00181 int u_hmap_new (u_hmap_opts_t *opts, u_hmap_t **hmap)
00182 {
00183 size_t i;
00184 u_hmap_t *c = NULL;
00185
00186 dbg_return_if (hmap == NULL, ~0);
00187
00188 dbg_return_if ((c = (u_hmap_t *) u_zalloc(sizeof(u_hmap_t))) == NULL, ~0);
00189
00190 if (opts == NULL)
00191 {
00192 dbg_err_if (u_hmap_opts_new(&c->opts));
00193 } else {
00194 c->opts = opts;
00195 dbg_err_if (_opts_check(c->opts));
00196 }
00197 dbg_err_if (_pcy_setup(c));
00198
00199 c->size = 0;
00200 dbg_err_if ((c->hmap = (struct u_hmap_e_s *)
00201 u_zalloc(sizeof(struct u_hmap_e_s) *
00202 c->opts->max_size)) == NULL);
00203
00204
00205 for (i = 0; i < c->opts->max_size; i++)
00206 LIST_INIT(&c->hmap[i]);
00207
00208 TAILQ_INIT(&c->pcy.queue);
00209
00210 *hmap = c;
00211
00212 return 0;
00213
00214 err:
00215 u_free(c);
00216 *hmap = NULL;
00217 return ~0;
00218 }
00219
00220 void u_hmap_dbg (u_hmap_t *hmap)
00221 {
00222 enum { MAX_LINE = 255 };
00223 u_string_t *s = NULL, *st = NULL;
00224 struct u_hmap_o_s *obj;
00225 size_t i;
00226
00227 dbg_ifb (hmap == NULL) return;
00228
00229 dbg ("<hmap>");
00230 for (i = 0; i < hmap->opts->max_size; i++)
00231 {
00232 dbg_ifb (u_string_create("", 1, &s)) return;
00233 dbg_err_if (u_string_clear(s));
00234 dbg_err_if (u_string_append(s, "|", 1));
00235
00236 LIST_FOREACH(obj, &hmap->hmap[i], next)
00237 {
00238 dbg_err_if (u_string_append(s, "[", 1));
00239 dbg_err_if (u_string_append(s, obj->key, strlen(obj->key)));
00240 dbg_err_if (u_string_append(s, ":", 1));
00241
00242 if (hmap->opts->f_str == NULL)
00243 {
00244 dbg_err_if (u_string_append(s, "*", 1));
00245 } else {
00246 st = hmap->opts->f_str(obj->val);
00247 dbg_err_if (u_string_append(s, u_string_c(st),
00248 u_string_len(st)-1));
00249 }
00250 dbg_err_if (u_string_append(s, "]", 1));
00251 }
00252 dbg_err_if (u_string_append(s, "|", 1));
00253 dbg(u_string_c(s));
00254 dbg_ifb (u_string_free(s)) return;
00255 }
00256 dbg("</hmap>");
00257 return;
00258
00259 err:
00260 u_string_free(s);
00261 return;
00262 }
00263
00274 int u_hmap_del (u_hmap_t *hmap, const char *key)
00275 {
00276 struct u_hmap_o_s *obj = NULL;
00277
00278 dbg_err_if (hmap == NULL);
00279 dbg_err_if (key == NULL);
00280
00281 if (_get(hmap, key, &obj))
00282 return ~0;
00283
00284 dbg_err_if (obj == NULL);
00285 LIST_REMOVE(obj, next);
00286 _o_free(hmap, obj);
00287 return 0;
00288
00289 err:
00290 return ~0;
00291 }
00292
00293 static int _get (u_hmap_t *hmap, const char *key,
00294 struct u_hmap_o_s **o)
00295 {
00296 struct u_hmap_o_s *obj;
00297 struct u_hmap_e_s *x;
00298 int comp;
00299
00300 dbg_err_if (hmap == NULL);
00301 dbg_err_if (key == NULL);
00302 dbg_err_if (o == NULL);
00303
00304 x = &hmap->hmap[hmap->opts->f_hash(key, hmap->opts->max_size)];
00305
00306 LIST_FOREACH(obj, x, next)
00307 {
00308 if ((comp = hmap->opts->f_comp(key, obj->key)) == 0)
00309 {
00310 *o = obj;
00311 return 0;
00312 } else if (comp < 0) {
00313 *o = NULL;
00314 break;
00315 }
00316 }
00317
00318 err:
00319 return ~0;
00320 }
00321
00322 void u_hmap_pcy_dbg (u_hmap_t *hmap)
00323 {
00324 struct u_hmap_queue_o_s *data;
00325 u_string_t *s = NULL;
00326
00327 dbg_ifb (hmap == NULL) return;
00328
00329 dbg_ifb (u_string_create("", 1, &s)) return;
00330 dbg_err_if (u_string_clear(s));
00331 dbg_err_if (u_string_append(s, "Policy: [", strlen("Policy: [")));
00332
00333 TAILQ_FOREACH(data, &hmap->pcy.queue, next)
00334 {
00335 dbg_err_if (u_string_append(s, "(", 1));
00336 dbg_err_if (u_string_append(s, data->key, strlen(data->key)));
00337 dbg_err_if (u_string_append(s, ")", 1));
00338 }
00339 dbg_err_if (u_string_append(s, "]", 1));
00340 dbg(u_string_c(s));
00341 dbg_if (u_string_free(s));
00342
00343 return;
00344
00345 err:
00346 dbg_if (u_string_free(s));
00347 return;
00348 }
00349
00350 static int _queue_pop_front (u_hmap_t *hmap)
00351 {
00352 struct u_hmap_queue_o_s *first;
00353
00354 dbg_err_if (hmap == NULL);
00355
00356 dbg_err_if ((first = TAILQ_FIRST(&hmap->pcy.queue)) == NULL);
00357 dbg_err_if (u_hmap_del(hmap, first->key));
00358 TAILQ_REMOVE(&hmap->pcy.queue, first, next);
00359 _data_o_free(first);
00360
00361 return 0;
00362
00363 err:
00364 return ~0;
00365 }
00366
00367 static int _queue_pop_back (u_hmap_t *hmap)
00368 {
00369 struct u_hmap_queue_o_s *last;
00370
00371 dbg_err_if (hmap == NULL);
00372
00373 dbg_err_if ((last = TAILQ_LAST(&hmap->pcy.queue, u_hmap_queue_h_s))
00374 == NULL);
00375 dbg_err_if (u_hmap_del(hmap, last->key));
00376 TAILQ_REMOVE(&hmap->pcy.queue, last, next);
00377 _data_o_free(last);
00378
00379 return 0;
00380
00381 err:
00382 return ~0;
00383 }
00384
00385 static int _queue_push (u_hmap_t *hmap, struct u_hmap_o_s *obj,
00386 struct u_hmap_queue_o_s **data)
00387 {
00388 struct u_hmap_queue_o_s *new;
00389
00390 dbg_err_if (hmap == NULL);
00391 dbg_err_if (obj == NULL);
00392 dbg_err_if (data == NULL);
00393
00394 if (*data == NULL)
00395 {
00396 dbg_err_if ((new = _data_o_new(obj->key)) == NULL);
00397 TAILQ_INSERT_HEAD(&hmap->pcy.queue, new, next);
00398 *data = new;
00399 } else {
00400 TAILQ_REMOVE(&hmap->pcy.queue, *data, next);
00401 TAILQ_INSERT_HEAD(&hmap->pcy.queue, *data, next);
00402 }
00403 return 0;
00404
00405 err:
00406 return ~0;
00407 }
00408
00409 static int _queue_push_count (u_hmap_t *hmap, struct u_hmap_o_s *obj,
00410 struct u_hmap_queue_o_s **counts)
00411 {
00412 struct u_hmap_queue_o_s *new, *t;
00413 int *count;
00414
00415 dbg_err_if (hmap == NULL);
00416 dbg_err_if (obj == NULL);
00417 dbg_err_if (counts == NULL);
00418
00419 if (*counts == NULL)
00420 {
00421 dbg_err_if ((new = _data_o_new(obj->key)) == NULL);
00422 TAILQ_INSERT_HEAD(&hmap->pcy.queue, new, next);
00423 *counts = TAILQ_FIRST(&hmap->pcy.queue);
00424 dbg_err_if ((count = (int *) u_zalloc(sizeof(int))) == NULL);
00425 new->o = (void *) count;
00426 *counts = new;
00427 } else {
00428 count = (int *) (*counts)->o;
00429 memset((void *) count, (*count)++, sizeof(int));
00430
00431 if ((t = TAILQ_NEXT(*counts, next)))
00432 {
00433 for (; t && ((*count) > *((int *) t->o)); t = TAILQ_NEXT(t, next))
00434 ;
00435 TAILQ_REMOVE(&hmap->pcy.queue, *counts, next);
00436 if (t)
00437 TAILQ_INSERT_BEFORE(t, *counts, next);
00438 else
00439 TAILQ_INSERT_TAIL(&hmap->pcy.queue, *counts, next);
00440 }
00441 }
00442 return 0;
00443
00444 err:
00445 return ~0;
00446 }
00447
00461 int u_hmap_put (u_hmap_t *hmap, const char *key, void *val)
00462 {
00463 struct u_hmap_o_s *obj, *new;
00464 struct u_hmap_e_s *x;
00465 int comp;
00466
00467 dbg_err_if (hmap == NULL);
00468 dbg_err_if (key == NULL);
00469 dbg_err_if (val == NULL);
00470
00471 dbg_err_if ((new = _o_new(key, val)) == NULL);
00472 x = &hmap->hmap[hmap->opts->f_hash(key, hmap->opts->max_size)];
00473
00474 if (hmap->opts->policy != U_HMAP_PCY_NONE &&
00475 hmap->size >= hmap->opts->max_elems)
00476 {
00477 dbg("Cache full - freeing according to policy %d", hmap->opts->policy);
00478 hmap->pcy.pop(hmap);
00479 }
00480
00481 if (LIST_EMPTY(x))
00482 {
00483 LIST_INSERT_HEAD(x, new, next);
00484 } else {
00485 LIST_FOREACH(obj, x, next)
00486 {
00487 if ((comp = hmap->opts->f_comp(key, obj->key)) == 0)
00488 {
00489
00490 LIST_INSERT_AFTER(obj, new, next);
00491 LIST_REMOVE(obj, next);
00492 _o_free(hmap, obj);
00493 goto end;
00494 } else {
00495 if (comp < 0)
00496 {
00497 LIST_INSERT_BEFORE(obj, new, next);
00498 break;
00499 } else if (!LIST_NEXT(obj, next)) {
00500 LIST_INSERT_AFTER(obj, new, next);
00501 break;
00502 }
00503 }
00504 }
00505 }
00506
00507 hmap->size++;
00508
00509 end:
00510 if ((hmap->pcy.ops & U_HMAP_PCY_OP_PUT) == U_HMAP_PCY_OP_PUT)
00511 hmap->pcy.push(hmap, new, &new->pqe);
00512
00513 return 0;
00514
00515 err:
00516 return ~0;
00517 }
00518
00532 int u_hmap_get (u_hmap_t *hmap, const char *key, void **val)
00533 {
00534 struct u_hmap_o_s *obj = NULL;
00535
00536 dbg_err_if (hmap == NULL);
00537 dbg_err_if (key == NULL);
00538 dbg_err_if (val == NULL);
00539
00540 if (_get(hmap, key, &obj))
00541 {
00542 *val = NULL;
00543 return ~0;
00544 }
00545 dbg_err_if (obj == NULL);
00546
00547 if ((hmap->pcy.ops & U_HMAP_PCY_OP_GET) == U_HMAP_PCY_OP_GET)
00548 hmap->pcy.push(hmap, obj, &obj->pqe);
00549
00550 *val = obj->val;
00551
00552 return 0;
00553
00554 err:
00555 return ~0;
00556 }
00557
00569 int u_hmap_foreach (u_hmap_t *hmap, int f(void *val))
00570 {
00571 struct u_hmap_o_s *obj;
00572 size_t i;
00573
00574 dbg_err_if (hmap == NULL);
00575 dbg_err_if (f == NULL);
00576
00577 for (i = 0; i < hmap->opts->max_size; i++)
00578 {
00579 LIST_FOREACH(obj, &hmap->hmap[i], next)
00580 dbg_err_if (f(obj->val));
00581 }
00582
00583 return 0;
00584
00585 err:
00586 return ~0;
00587 }
00588
00600 int u_hmap_free (u_hmap_t *hmap)
00601 {
00602 struct u_hmap_o_s *obj;
00603 struct u_hmap_queue_o_s *data;
00604 size_t i;
00605
00606 dbg_return_if (hmap == NULL, ~0);
00607
00608
00609 for (i = 0; i < hmap->opts->max_size; i++)
00610 {
00611 while ((obj = LIST_FIRST(&hmap->hmap[i])) != NULL)
00612 {
00613 LIST_REMOVE(obj, next);
00614 _o_free(hmap, obj);
00615 }
00616 }
00617
00618 u_free(hmap->hmap);
00619
00620
00621 while ((data = TAILQ_FIRST(&hmap->pcy.queue)) != NULL)
00622 {
00623 TAILQ_REMOVE(&hmap->pcy.queue, data, next);
00624 _data_o_free(data);
00625 }
00626
00627 u_free(hmap->opts);
00628 u_free(hmap);
00629
00630 return 0;
00631 }
00632
00644 int u_hmap_opts_new (u_hmap_opts_t **opts)
00645 {
00646 u_hmap_opts_t *o;
00647
00648 dbg_err_if (opts == NULL);
00649
00650 dbg_err_if ((o = (u_hmap_opts_t *) u_zalloc(sizeof(u_hmap_opts_t)))
00651 == NULL);
00652
00653
00654 o->max_size = U_HMAP_MAX_SIZE;
00655 o->max_elems = U_HMAP_MAX_ELEMS;
00656 o->policy = U_HMAP_PCY_NONE;
00657 o->f_hash = &_f_hash;
00658 o->f_comp = &_f_comp;
00659 o->f_free = &_f_free;
00660 o->f_str = NULL;
00661
00662 *opts = o;
00663
00664 return 0;
00665 err:
00666 *opts = NULL;
00667 return ~0;
00668 }
00669
00670 void u_hmap_opts_dbg (u_hmap_opts_t *opts)
00671 {
00672 dbg_ifb (opts == NULL) return;
00673
00674 dbg("[%u - %d,%d,%d,%x,%x,%x,%x]",
00675 sizeof(u_hmap_opts_t),
00676 opts->policy,
00677 opts->max_size,
00678 opts->max_elems,
00679 opts->f_hash,
00680 opts->f_comp,
00681 opts->f_free,
00682 opts->f_str);
00683 }
00684
00685 static struct u_hmap_o_s *_o_new (const char *key, void *val)
00686 {
00687 struct u_hmap_o_s *obj;
00688
00689 dbg_return_if (key == NULL, NULL);
00690 dbg_return_if (val == NULL, NULL);
00691
00692 dbg_return_if ((obj = (struct u_hmap_o_s *)
00693 u_zalloc(sizeof(struct u_hmap_o_s))) == NULL, NULL);
00694
00695 dbg_err_if ((obj->key = strdup(key)) == NULL);
00696 obj->val = val;
00697 obj->pqe = NULL;
00698
00699 return obj;
00700
00701 err:
00702 u_free(obj);
00703 return NULL;
00704 }
00705
00706 static void _o_free (u_hmap_t *hmap, struct u_hmap_o_s *obj)
00707 {
00708 dbg_ifb (hmap == NULL) return;
00709 dbg_ifb (obj == NULL) return;
00710
00711 hmap->opts->f_free(obj->val);
00712 u_free(obj->key);
00713 u_free(obj);
00714 }
00715
00716 static struct u_hmap_queue_o_s *_data_o_new (const char *key)
00717 {
00718 struct u_hmap_queue_o_s *data;
00719
00720 dbg_return_if (key == NULL, NULL);
00721
00722 dbg_return_if ((data = (struct u_hmap_queue_o_s *)
00723 u_zalloc(sizeof(struct u_hmap_queue_o_s))) == NULL,
00724 NULL);
00725
00726 dbg_err_if ((data->key = strdup(key)) == NULL);
00727 data->o = NULL;
00728
00729 return data;
00730
00731 err:
00732 u_free(data);
00733 return NULL;
00734 }
00735
00736 static void _data_o_free (struct u_hmap_queue_o_s *data)
00737 {
00738 dbg_ifb (data == NULL) return;
00739
00740 u_free(data->o);
00741 u_free(data->key);
00742 u_free(data);
00743 }
00744