Main Page | Modules | Directories | File List | Globals | Related Pages

map.c

Go to the documentation of this file.
00001 #ifndef _MAP_C_ /* -*- linux-c -*- */
00002 #define _MAP_C_
00003 
00004 /** @file map.c
00005  * @brief Implements maps (associative arrays) and lists
00006  */
00007 
00008 #include "map.h"
00009 #include "alloc.c"
00010 #include "string.c"
00011 
00012 static int map_sizes[] = {
00013         sizeof(struct map_node_int64),
00014         sizeof(struct map_node_stat),
00015         sizeof(struct map_node_str),
00016         0
00017 };
00018 
00019 static unsigned string_hash(const char *key1, const char *key2)
00020 {
00021         int hash = 0, count = 0;
00022         char *v1 = (char *)key1;
00023         char *v2 = (char *)key2;
00024         while (*v1 && count++ < 5) {
00025                 hash += *v1++;
00026         }
00027         while (v2 && *v2 && count++ < 5) {
00028                 hash += *v2++;
00029         }
00030         return hash_long((unsigned long)hash, HASH_TABLE_BITS);
00031 }
00032 
00033 static unsigned mixed_hash(const char *key1, long key2)
00034 {
00035         int hash = 0, count = 0;
00036         char *v = (char *)key1;
00037         while (v && *v && count++ < 5)
00038                 hash += *v++;
00039         return hash_long((unsigned long)(hash ^ key2), HASH_TABLE_BITS);
00040 }
00041 
00042 /** @addtogroup maps 
00043  * Implements maps (associative arrays) and lists
00044  * @{ 
00045  */
00046 
00047 /** Create a new map.
00048  * Maps must be created at module initialization time.
00049  * @param max_entries The maximum number of entries allowed. Currently that number will
00050  * be preallocated.  If more entries are required, the oldest ones will be deleted. This makes
00051  * it effectively a circular buffer.  If max_entries is 0, there will be no maximum and entries
00052  * will be allocated dynamically.
00053  * @param type Type of values stored in this map. 
00054  * @return A MAP on success or NULL on failure.
00055  */
00056 
00057 MAP _stp_map_new(unsigned max_entries, enum valtype type)
00058 {
00059         size_t size;
00060         MAP m = (MAP) _stp_valloc(sizeof(struct map_root));
00061         if (m == NULL)
00062                 return NULL;
00063 
00064         INIT_LIST_HEAD(&m->head);
00065 
00066         m->maxnum = max_entries;
00067         m->type = type;
00068         if (type >= END) {
00069                 dbug ("map_new: unknown type %d\n", type);
00070                 return NULL;
00071         }
00072 
00073         if (max_entries) {
00074                 void *tmp;
00075                 int i;
00076                 struct list_head *e;
00077 
00078                 INIT_LIST_HEAD(&m->pool);
00079                 size = map_sizes[type];
00080                 tmp = _stp_valloc(max_entries * size);
00081 
00082                 for (i = max_entries - 1; i >= 0; i--) {
00083                         e = i * size + tmp;
00084                         dbug ("e=%lx\n", (long)e);
00085                         list_add(e, &m->pool);
00086                 }
00087                 m->membuf = tmp;
00088         }
00089         return m;
00090 }
00091 
00092 static void map_free_strings(MAP map, struct map_node *n)
00093 {
00094         struct map_node_str *m = (struct map_node_str *)n;
00095         dbug ("n = %lx\n", (long)n);
00096         if (map->type == STRING) {
00097                 dbug ("val STRING %lx\n", (long)m->str);
00098                 if (m->str)
00099                         _stp_free(m->str);
00100         }
00101         if (m->n.key1type == STR) {
00102                 dbug ("key1 STR %lx\n", (long)key1str(m));
00103                 if (key1str(m))
00104                         _stp_free(key1str(m));
00105         }
00106         if (m->n.key2type == STR) {
00107                 dbug ("key2 STR %lx\n", (long)key2str(m));
00108                 if (key2str(m))
00109                         _stp_free(key2str(m));
00110         }
00111 }
00112 
00113 /** Deletes the current element.
00114  * If no current element (key) for this map is set, this function does nothing.
00115  * @param map 
00116  */
00117 
00118 void _stp_map_key_del(MAP map)
00119 {
00120         struct map_node *m;
00121 
00122         dbug ("create=%d key=%lx\n", map->create, (long)map->key);
00123         if (map == NULL)
00124                 return;
00125 
00126         if (map->create) {
00127                 map->create = 0;
00128                 map->key = NULL;
00129                 return;
00130         }
00131 
00132         if (map->key == NULL)
00133                 return;
00134 
00135         m = (struct map_node *)map->key;
00136 
00137         /* remove node from old hash list */
00138         hlist_del_init(&m->hnode);
00139 
00140         /* remove from entry list */
00141         list_del(&m->lnode);
00142 
00143         /* remove any allocated string storage */
00144         map_free_strings(map, (struct map_node *)map->key);
00145 
00146         if (map->maxnum)
00147                 list_add(&m->lnode, &map->pool);
00148         else
00149                 _stp_free(m);
00150 
00151         map->key = NULL;
00152         map->num--;
00153 }
00154 
00155 /** Get the first element in a map.
00156  * @param map 
00157  * @returns a pointer to the first element.
00158  * This is typically used with _stp_map_iter().  See the foreach() macro
00159  * for typical usage.  It probably does what you want anyway.
00160  * @sa foreach
00161  */
00162 
00163 struct map_node *_stp_map_start(MAP map)
00164 {
00165         if (map == NULL)
00166                 return NULL;
00167 
00168         dbug ("%lx\n", (long)map->head.next);
00169 
00170         if (list_empty(&map->head))
00171                 return NULL;
00172 
00173         return (struct map_node *)map->head.next;
00174 }
00175 
00176 /** Get the next element in a map.
00177  * @param map 
00178  * @param m a pointer to the current element, returned from _stp_map_start()
00179  * or _stp_map_iter().
00180  * @returns a pointer to the next element.
00181  * This is typically used with _stp_map_start().  See the foreach() macro
00182  * for typical usage.  It probably does what you want anyway.
00183  * @sa foreach
00184  */
00185 
00186 struct map_node *_stp_map_iter(MAP map, struct map_node *m)
00187 {
00188         if (map == NULL)
00189                 return NULL;
00190 
00191         dbug ("%lx next=%lx  prev=%lx  map->head.next=%lx\n", (long)m, 
00192               (long)m->lnode.next, (long)m->lnode.prev, (long)map->head.next);
00193 
00194         if (m->lnode.next == &map->head)
00195                 return NULL;
00196 
00197         return (struct map_node *)m->lnode.next;
00198 }
00199 
00200 /** Deletes a map.
00201  * Deletes a map, freeing all memory in all elements.  Normally done only when the module exits.
00202  * @param map
00203  */
00204 
00205 void _stp_map_del(MAP map)
00206 {
00207         if (map == NULL)
00208                 return;
00209 
00210         if (!list_empty(&map->head)) {
00211                 struct map_node *ptr = (struct map_node *)map->head.next;
00212                 while (ptr && ptr != (struct map_node *)&map->head) {
00213                         map_free_strings(map, ptr);
00214                         ptr = (struct map_node *)ptr->lnode.next;
00215                 }
00216         }
00217         _stp_vfree(map->membuf);
00218         _stp_vfree(map);
00219 }
00220 
00221 /**********************  KEY FUNCTIONS *********************/
00222 
00223 
00224 /** Set the map's key to two longs.
00225  * This sets the current element based on a key of two strings. If the keys are
00226  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00227  * call.
00228  * @param map
00229  * @param key1 first key
00230  * @param key2 second key
00231  */
00232 
00233 void _stp_map_key_long_long(MAP map, long key1, long key2)
00234 {
00235         unsigned hv;
00236         struct hlist_head *head;
00237         struct hlist_node *e;
00238 
00239         if (map == NULL)
00240                 return;
00241 
00242         hv = hash_long(key1 ^ key2, HASH_TABLE_BITS);
00243         head = &map->hashes[hv];
00244 
00245         dbug ("hash for %ld,%ld is %d\n", key1, key2, hv);
00246 
00247         hlist_for_each(e, head) {
00248                 struct map_node *n =
00249                         (struct map_node *)((long)e - sizeof(struct hlist_node));
00250                 dbug ("n =%lx  key=%ld,%ld\n", (long)n, n->key1.val, n->key2.val);
00251                 if (key1 == n->key1.val && key2 == n->key2.val) {
00252                         map->key = n;
00253                         dbug ("saving key %lx\n", (long)map->key);
00254                         map->create = 0;
00255                         return;
00256                 }
00257         }
00258 
00259         map->c_key1.val = key1;
00260         map->c_key2.val = key2;
00261         map->c_key1type = LONG;
00262         map->c_key2type = LONG;
00263         map->c_keyhead = head;
00264         map->create = 1;
00265 }
00266 
00267 /** Set the map's key to two strings.
00268  * This sets the current element based on a key of two strings. If the keys are
00269  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00270  * call.
00271  * @param map
00272  * @param key1 first key
00273  * @param key2 second key
00274  */
00275 
00276 void _stp_map_key_str_str(MAP map, char *key1, char *key2)
00277 {
00278         unsigned hv;
00279         struct hlist_head *head;
00280         struct hlist_node *e;
00281 
00282         if (map == NULL)
00283                 return;
00284 
00285         if (key1 == NULL) {
00286                 map->key = NULL;
00287                 return;
00288         }
00289 
00290         hv = string_hash(key1, key2);
00291         head = &map->hashes[hv];
00292 
00293         dbug ("hash for %s,%s is %d\n", key1, key2, hv);
00294 
00295         hlist_for_each(e, head) {
00296                 struct map_node *n =
00297                         (struct map_node *)((long)e - sizeof(struct hlist_node));
00298                 dbug ("e =%lx  key=%s,%s\n", (long)e, n->key1.str,n->key2.str);
00299                 if (strcmp(key1, n->key1.str) == 0
00300                     && (key2 == NULL || strcmp(key2, n->key2.str) == 0)) {
00301                         map->key = n;
00302                         dbug ("saving key %lx\n", (long)map->key);
00303                         map->create = 0;
00304                         return;
00305                 }
00306         }
00307 
00308         map->c_key1.str = key1;
00309         map->c_key2.str = key2;
00310         map->c_key1type = STR;
00311         map->c_key2type = STR;
00312         map->c_keyhead = head;
00313         map->create = 1;
00314 }
00315 
00316 /** Set the map's key to a string and a long.
00317  * This sets the current element based on a key of a string and a long. If the keys are
00318  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00319  * call.
00320  * @param map
00321  * @param key1 first key
00322  * @param key2 second key
00323  */
00324 
00325 void _stp_map_key_str_long(MAP map, char *key1, long key2)
00326 {
00327         unsigned hv;
00328         struct hlist_head *head;
00329         struct hlist_node *e;
00330 
00331         if (map == NULL)
00332                 return;
00333 
00334         if (key1 == NULL) {
00335                 map->key = NULL;
00336                 return;
00337         }
00338 
00339         hv = mixed_hash(key1, key2);
00340         head = &map->hashes[hv];
00341 
00342         dbug ("hash for %s,%ld is %d\n", key1, key2, hv);
00343 
00344         hlist_for_each(e, head) {
00345                 struct map_node *n =
00346                         (struct map_node *)((long)e - sizeof(struct hlist_node));
00347                 dbug ("e =%lx  key=%s,%ld\n", (long)e, n->key1.str,(long)n->key2.val);
00348                 if (strcmp(key1, n->key1.str) == 0 && key2 == n->key2.val) {
00349                         map->key = n;
00350                         dbug ("saving key %lx\n", (long)map->key);
00351                         map->create = 0;
00352                         return;
00353                 }
00354         }
00355 
00356         map->c_key1.str = key1;
00357         map->c_key2.val = key2;
00358         map->c_key1type = STR;
00359         map->c_key2type = LONG;
00360         map->c_keyhead = head;
00361         map->create = 1;
00362 }
00363 
00364 /** Set the map's key to a long and a string.
00365  * This sets the current element based on a key of a long and a string. If the keys are
00366  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00367  * call.
00368  * @param map
00369  * @param key1 first key
00370  * @param key2 second key
00371  */
00372 
00373 void _stp_map_key_long_str(MAP map, long key1, char *key2)
00374 {
00375         unsigned hv;
00376         struct hlist_head *head;
00377         struct hlist_node *e;
00378 
00379         if (map == NULL)
00380                 return;
00381 
00382         hv = mixed_hash(key2, key1);
00383         head = &map->hashes[hv];
00384         dbug ("hash for %ld,%s is %d\n", key1, key2, hv);
00385 
00386         hlist_for_each(e, head) {
00387                 struct map_node *n =
00388                         (struct map_node *)((long)e - sizeof(struct hlist_node));
00389                 dbug ("e =%lx  key=%ld,%s\n", (long)e, n->key1.val,n->key2.str);
00390                 if (key1 == n->key1.val && strcmp(key2, n->key2.str) == 0) {
00391                         map->key = n;
00392                         dbug ("saving key %lx\n", (long)map->key);
00393                         map->create = 0;
00394                         return;
00395                 }
00396         }
00397 
00398         map->c_key1.val = key1;
00399         map->c_key2.str = key2;
00400         map->c_key1type = LONG;
00401         map->c_key2type = STR;
00402         map->c_keyhead = head;
00403         map->create = 1;
00404 }
00405 
00406 /** Set the map's key to a string.
00407  * This sets the current element based on a string key. If the key is
00408  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00409  * call.
00410  * @param map
00411  * @param key
00412  */
00413 
00414 void _stp_map_key_str(MAP map, char *key)
00415 {
00416         if (map == NULL)
00417                 return;
00418         _stp_map_key_str_str(map, key, NULL);
00419         map->c_key2type = NONE;
00420 }
00421 
00422 /** Set the map's key to a long.
00423  * This sets the current element based on a long key. If the key is
00424  * not found, a new element will not be created until a <i>_stp_map_set_xxx</i>
00425  * call.
00426  * @param map
00427  * @param key 
00428  */
00429 
00430 void _stp_map_key_long(MAP map, long key)
00431 {
00432         if (map == NULL)
00433                 return;
00434         _stp_map_key_long_long(map, key, 0);
00435         map->c_key2type = NONE;
00436 }
00437 
00438 /**********************  SET/GET VALUES *********************/
00439 
00440 static void map_copy_keys(MAP map, struct map_node *m)
00441 {
00442         m->key1type = map->c_key1type;
00443         m->key2type = map->c_key2type;
00444         switch (map->c_key1type) {
00445         case STR:
00446                 m->key1.str = _stp_alloc(strlen(map->c_key1.str) + 1);
00447                 strcpy(m->key1.str, map->c_key1.str);
00448                 break;
00449         case LONG:
00450                 m->key1.val = map->c_key1.val;
00451                 break;
00452         case NONE:
00453                 /* ERROR */
00454                 break;
00455         }
00456         switch (map->c_key2type) {
00457         case STR:
00458                 m->key2.str = _stp_alloc(strlen(map->c_key2.str) + 1);
00459                 strcpy(m->key2.str, map->c_key2.str);
00460                 break;
00461         case LONG:
00462                 m->key2.val = map->c_key2.val;
00463                 break;
00464         case NONE:
00465                 break;
00466         }
00467 
00468         /* add node to new hash list */
00469         hlist_add_head(&m->hnode, map->c_keyhead);
00470         
00471         map->key = m;
00472         map->create = 0;
00473         map->num++;
00474 }
00475 
00476 static void __stp_map_set_int64(MAP map, int64_t val, int add)
00477 {
00478         struct map_node_int64 *m;
00479 
00480         if (map == NULL)
00481                 return;
00482 
00483         if (map->create) {
00484                 if (val == 0)
00485                         return;
00486 
00487                 if (map->maxnum) {
00488                         if (list_empty(&map->pool)) {
00489                                 if (map->no_wrap) {
00490                                         /* ERROR. FIXME */
00491                                         return;
00492                                 }
00493                                 m = (struct map_node_int64 *)map->head.next;
00494                                 hlist_del_init(&m->n.hnode);
00495                                 map_free_strings(map, (struct map_node *)m);
00496                                 dbug ("got %lx off head\n", (long)m);
00497                         } else {
00498                                 m = (struct map_node_int64 *)map->pool.next;
00499                                 dbug ("got %lx off pool\n", (long)m);
00500                         }
00501                         list_move_tail(&m->n.lnode, &map->head);
00502                 } else {
00503                         m = (struct map_node_int64 *)
00504                             _stp_calloc(sizeof(struct map_node_int64));
00505                         /* add node to list */
00506                         list_add_tail(&m->n.lnode, &map->head);
00507                 }
00508 
00509                 /* copy the key(s) */
00510                 map_copy_keys(map, &m->n);
00511 
00512                 /* set the value */
00513                 m->val = val;
00514         } else {
00515                 if (map->key == NULL)
00516                         return;
00517 
00518                 if (val) {
00519                         m = (struct map_node_int64 *)map->key;
00520                         if (add)
00521                                 m->val += val;
00522                         else
00523                                 m->val = val;
00524                 } else if (!add) {
00525                         /* setting value to 0 is the same as deleting */
00526                         _stp_map_key_del(map);
00527                 }
00528         }
00529 }
00530 
00531 /** Set the current element's value to an int64.
00532  * This sets the current element's value to an int64. The map must have been created
00533  * to hold int64s using _stp_map_new()
00534  *
00535  * If the element doesn't exist, it is created.  If no current element (key)
00536  * is set for the map, this function does nothing.
00537  * @param map
00538  * @param val new value
00539  * @sa _stp_map_add_int64
00540  * @sa _stp_map_set()
00541  */
00542 void _stp_map_set_int64(MAP map, int64_t val)
00543 {
00544         __stp_map_set_int64 (map, val, 0);
00545 }
00546 
00547 
00548 /** Adds an int64 to the current element's value.
00549  * This adds an int64 to the current element's value. The map must have been created
00550  * to hold int64s using _stp_map_new()
00551  *
00552  * If the element doesn't exist, it is created.  If no current element (key)
00553  * is set for the map, this function does nothing.
00554  * @param map
00555  * @param val value
00556  * @sa _stp_map_set_int64
00557  */
00558 
00559 void _stp_map_add_int64(MAP map, int64_t val)
00560 {
00561         __stp_map_set_int64 (map, val, 1);
00562 }
00563 
00564 /** Gets the current element's value.
00565  * @param map
00566  * @returns The value. If the current element is not set or doesn't exist, returns 0.
00567  */
00568 
00569 int64_t _stp_map_get_int64(MAP map)
00570 {
00571         struct map_node_int64 *m;
00572         if (map == NULL || map->create || map->key == NULL)
00573                 return 0;
00574         dbug ("%lx\n", (long)map->key);
00575         m = (struct map_node_int64 *)map->key;
00576         return m->val;
00577 }
00578 
00579 /** Set the current element's value to a C string.
00580  * This sets the current element's value to an C string. The map must have been created
00581  * to hold int64s using <i>_stp_map_new(xxx, STRING)</i>
00582  *
00583  * If the element doesn't exist, it is created.  If no current element (key)
00584  * is set for the map, this function does nothing.
00585  * @param map
00586  * @param val new string
00587  * @sa _stp_map_set()
00588  */
00589 
00590 void _stp_map_set_str(MAP map, char *val)
00591 {
00592         struct map_node_str *m;
00593 
00594         if (map == NULL)
00595                 return;
00596 
00597         if (map->create) {
00598                 if (val == NULL)
00599                         return;
00600 
00601                 if (map->maxnum) {
00602                         if (list_empty(&map->pool)) {
00603                                 if (map->no_wrap) {
00604                                         /* ERROR. FIXME */
00605                                         return;
00606                                 }
00607                                 m = (struct map_node_str *)map->head.next;
00608                                 hlist_del_init(&m->n.hnode);
00609                                 map_free_strings(map, (struct map_node *)m);
00610                                 dbug ("got %lx off head\n", (long)m);
00611                         } else {
00612                                 m = (struct map_node_str *)map->pool.next;
00613                                 dbug ("got %lx off pool\n", (long)m);
00614                         }
00615                         list_move_tail(&m->n.lnode, &map->head);
00616                 } else {
00617                         m = (struct map_node_str *)
00618                             _stp_calloc(sizeof(struct map_node_str));
00619                         /* add node to list */
00620                         list_add_tail(&m->n.lnode, &map->head);
00621                 }
00622 
00623                 /* copy the key(s) */
00624                 map_copy_keys(map, &m->n);
00625 
00626                 /* set the value */
00627                 m->str = _stp_alloc(strlen(val) + 1);
00628                 strcpy(m->str, val);
00629         } else {
00630                 if (map->key == NULL)
00631                         return;
00632 
00633                 if (val) {
00634                         m = (struct map_node_str *)map->key;
00635                         if (m->str)
00636                                 _stp_free(m->str);
00637                         m->str = _stp_alloc(strlen(val) + 1);
00638                         strcpy(m->str, val);
00639                 } else {
00640                         /* setting value to 0 is the same as deleting */
00641                         _stp_map_key_del(map);
00642                 }
00643         }
00644 }
00645 
00646 /** Set the current element's value to String.
00647  * This sets the current element's value to a String. The map must have been created
00648  * to hold int64s using <i>_stp_map_new(xxx, STRING)</i>
00649  *
00650  * If the element doesn't exist, it is created.  If no current element (key)
00651  * is set for the map, this function does nothing.
00652  * @param map
00653  * @param str String containing new value.
00654  * @sa _stp_map_set()
00655  */
00656 
00657 void _stp_map_set_string (MAP map, String str)
00658 {
00659   _stp_map_set_str (map, str->buf);
00660 }
00661 
00662 /** Gets the current element's value.
00663  * @param map
00664  * @returns A string pointer. If the current element is not set or doesn't exist, returns NULL.
00665  */
00666 
00667 char *_stp_map_get_str(MAP map)
00668 {
00669         struct map_node_str *m;
00670         if (map == NULL || map->create || map->key == NULL)
00671                 return NULL;
00672         dbug ("%lx\n", (long)map->key);
00673         m = (struct map_node_str *)map->key;
00674         return m->str;
00675 }
00676 
00677 /** Set the current element's value to a stat.
00678  * This sets the current element's value to an stat struct. The map must have been created
00679  * to hold stats using <i>_stp_map_new(xxx, STAT)</i>.  This function would only be used
00680  * if we wanted to set stats to something other than the normal initial values (count = 0,
00681  * sum = 0, etc).  It may be deleted if it doesn't turn out to be useful.
00682  * @sa _stp_map_stat_add 
00683  *
00684  * If the element doesn't exist, it is created.  If no current element (key)
00685  * is set for the map, this function does nothing.
00686  * @param map
00687  * @param stats pointer to stats struct.
00688  * @todo Histograms don't work yet.
00689  */
00690 
00691 void _stp_map_set_stat(MAP map, stat * stats)
00692 {
00693         struct map_node_stat *m;
00694 
00695         if (map == NULL)
00696                 return;
00697         dbug ("set_stat %lx\n", (long)map->key);
00698 
00699         if (map->create) {
00700                 if (stats == NULL)
00701                         return;
00702 
00703                 if (map->maxnum) {
00704                         if (list_empty(&map->pool)) {
00705                                 if (map->no_wrap) {
00706                                         /* ERROR. FIXME */
00707                                         return;
00708                                 }
00709                                 m = (struct map_node_stat *)map->head.next;
00710                                 hlist_del_init(&m->n.hnode);
00711                                 map_free_strings(map, (struct map_node *)m);
00712                                 dbug ("got %lx off head\n", (long)m);
00713                         } else {
00714                                 m = (struct map_node_stat *)map->pool.next;
00715                                 dbug ("got %lx off pool\n", (long)m);
00716                         }
00717                         list_move_tail(&m->n.lnode, &map->head);
00718                 } else {
00719                         m = (struct map_node_stat *)
00720                             _stp_calloc(sizeof(struct map_node_stat));
00721                         /* add node to list */
00722                         list_add_tail(&m->n.lnode, &map->head);
00723                 }
00724 
00725                 /* copy the key(s) */
00726                 map_copy_keys(map, &m->n);
00727 
00728                 /* set the value */
00729                 memcpy(&m->stats, stats, sizeof(stat));
00730         } else {
00731                 if (map->key == NULL)
00732                         return;
00733 
00734                 if (stats) {
00735                         m = (struct map_node_stat *)map->key;
00736                         memcpy(&m->stats, stats, sizeof(stat));
00737                 } else {
00738                         /* setting value to NULL is the same as deleting */
00739                         _stp_map_key_del(map);
00740                 }
00741         }
00742 }
00743 
00744 /** Gets the current element's value.
00745  * @param map
00746  * @returns A pointer to the stats struct. If the current element is not set 
00747  * or doesn't exist, returns NULL.
00748  */
00749 
00750 stat *_stp_map_get_stat(MAP map)
00751 {
00752         struct map_node_stat *m;
00753         if (map == NULL || map->create || map->key == NULL)
00754                 return NULL;
00755         dbug ("%lx\n", (long)map->key);
00756         m = (struct map_node_stat *)map->key;
00757         return &m->stats;
00758 }
00759 
00760 /** Add to the current element's statistics.
00761  * Increments the statistics counter by one and the sum by <i>val</i>.
00762  * Adjusts minimum, maximum, and histogram.
00763  *
00764  * If the element doesn't exist, it is created.  If no current element (key)
00765  * is set for the map, this function does nothing.
00766  * @param map
00767  * @param val value to add to the statistics
00768  * @todo Histograms don't work yet.
00769  */
00770 
00771 void _stp_map_stat_add(MAP map, int64_t val)
00772 {
00773         struct map_node_stat *m;
00774         if (map == NULL)
00775                 return;
00776 
00777         if (map->create) {
00778                 stat st = { 1, val, val, val };
00779                 /* histogram */
00780                 _stp_map_set_stat(map, &st);
00781                 return;
00782         }
00783 
00784         if (map->key == NULL)
00785                 return;
00786 
00787         dbug ("add_stat %lx\n", (long)map->key);
00788         m = (struct map_node_stat *)map->key;
00789         m->stats.count++;
00790         m->stats.sum += val;
00791         if (val > m->stats.max)
00792                 m->stats.max = val;
00793         if (val < m->stats.min)
00794                 m->stats.min = val;
00795         /* histogram */
00796 }
00797 
00798 /** @} */
00799 
00800 /**********************  List Functions *********************/
00801 
00802 /** @addtogroup lists
00803  * Lists are special cases of maps.
00804  * @b Example:
00805  * @include list.c
00806  * @{ */
00807 
00808 /** Create a new list.
00809  * A list is a map that internally has an incrementing long key for each member.
00810  * Lists do not wrap if elements are added to exceed their maximum size.
00811  * @param max_entries The maximum number of entries allowed. Currently that number will
00812  * be preallocated.  If max_entries is 0, there will be no maximum and entries
00813  * will be allocated dynamically.
00814  * @param type Type of values stored in this list. 
00815  * @return A MAP on success or NULL on failure.
00816  * @sa foreach
00817  */
00818 
00819 MAP _stp_list_new(unsigned max_entries, enum valtype type)
00820 {
00821   MAP map = _stp_map_new (max_entries, type);
00822   map->no_wrap = 1;
00823   return map;
00824 }
00825 
00826 /** Clears a list.
00827  * All elements in the list are deleted.
00828  * @param map 
00829  */
00830 
00831 void _stp_list_clear(MAP map)
00832 {
00833         if (map == NULL)
00834                 return;
00835 
00836         if (!list_empty(&map->head)) {
00837                 struct map_node *ptr = (struct map_node *)map->head.next;
00838 
00839                 while (ptr && ptr != (struct map_node *)&map->head) {
00840                         struct map_node *next = (struct map_node *)ptr->lnode.next;
00841 
00842                         /* remove node from old hash list */
00843                         hlist_del_init(&ptr->hnode);
00844 
00845                         /* remove from entry list */
00846                         list_del(&ptr->lnode);
00847                         
00848                         /* remove any allocated string storage */
00849                         map_free_strings(map, ptr);
00850                         
00851                         if (map->maxnum)
00852                                 list_add(&ptr->lnode, &map->pool);
00853                         else
00854                                 _stp_free(ptr);
00855 
00856                         map->num--;
00857                         ptr = next;
00858                 }
00859         }
00860 
00861         if (map->num != 0) {
00862                 _stp_log ("ERROR: list is supposed to be empty (has %d)\n", map->num);
00863         }
00864 }
00865 
00866 /** Adds a C string to a list.
00867  * @param map
00868  * @param str
00869  * @sa _stp_list_add()
00870  */
00871 
00872 inline void _stp_list_add_str(MAP map, char *str)
00873 {
00874         _stp_map_key_long(map, map->num);
00875         _stp_map_set_str(map, str);
00876 }
00877 
00878 /** Adds a String to a list.
00879  * @param map
00880  * @param str String to add.
00881  * @sa _stp_list_add()
00882  */
00883 
00884 inline void _stp_list_add_string (MAP map, String str)
00885 {
00886         _stp_map_key_long(map, map->num);
00887         _stp_map_set_str(map, str->buf);
00888 }
00889 
00890 /** Adds an int64 to a list.
00891  * @param map
00892  * @param val
00893  * @sa _stp_list_add()
00894  */
00895 
00896 inline void _stp_list_add_int64(MAP map, int64_t val)
00897 {
00898         _stp_map_key_long(map, map->num);
00899         _stp_map_set_int64(map, val);
00900 }
00901 
00902 /** Get the number of elements in a list.
00903  * @param map
00904  * @returns The number of elements in a list.
00905  */
00906 
00907 inline int _stp_list_size(MAP map)
00908 {
00909         return map->num;
00910 }
00911 /** @} */
00912 #endif /* _MAP_C_ */