Main Page | Modules | Data Structures | File List | Data Fields

hmap.c

00001 /* $Id: hmap.c,v 1.7 2006/04/20 09:53:53 tat Exp $ */
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 <u/memory.h>
00010 #include <u/carpal.h>
00011 #include <u/queue.h>
00012 #include <u/str.h>
00013 #include <u/hmap.h>
00014 
00020 /* default limits handled by policies */
00021 #define U_HMAP_MAX_SIZE      512
00022 #define U_HMAP_MAX_ELEMS     U_HMAP_MAX_SIZE
00023 
00024 
00025 /* policy queue object */
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 /* hmap object abstraction */
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 /* hmap policy representation */
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 /* hmap representation */
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     /* initialise entries */
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) /* object found */
00309         { 
00310             *o = obj;
00311             return 0;
00312         } else if (comp < 0) { /* cannot be in list (ordered) */
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     {  /* no reference to queue entry */
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 { /* have element in queue - move to head */
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) /* no reference to queue entry */
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 { /* have element in queue - move to head */
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                 /* object already hmapd -> overwrite */
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     /* free the hashhmap */
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     /* free the policy queue */
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     /* set defaults */
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);  /* custom object deletion */
00712     u_free(obj->key);  /* strdup()ed 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 

←Products
© 2005-2006 - KoanLogic S.r.l. - All rights reserved