Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

map.c

Go to the documentation of this file.
00001 #ifndef _MAP_C_
00002 #define _MAP_C_
00003 
00004 /* -*- linux-c -*- */
00005 /** @file map.c
00006  * @brief Implements maps (associative arrays) and lists
00007  */
00008 
00009 #include "map.h"
00010 #include "alloc.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  */
00541 void _stp_map_set_int64(MAP map, int64_t val)
00542 {
00543         __stp_map_set_int64 (map, val, 0);
00544 }
00545 
00546 
00547 /** Adds an int64 to the current element's value.
00548  * This adds an int64 to the current element's value. The map must have been created
00549  * to hold int64s using _stp_map_new()
00550  *
00551  * If the element doesn't exist, it is created.  If no current element (key)
00552  * is set for the map, this function does nothing.
00553  * @param map
00554  * @param val value
00555  * @sa _stp_map_set_int64
00556  */
00557 
00558 void _stp_map_add_int64(MAP map, int64_t val)
00559 {
00560         __stp_map_set_int64 (map, val, 1);
00561 }
00562 
00563 /** Gets the current element's value.
00564  * @param map
00565  * @returns The value. If the current element is not set or doesn't exist, returns 0.
00566  */
00567 
00568 int64_t _stp_map_get_int64(MAP map)
00569 {
00570         struct map_node_int64 *m;
00571         if (map == NULL || map->create || map->key == NULL)
00572                 return 0;
00573         dbug ("%lx\n", (long)map->key);
00574         m = (struct map_node_int64 *)map->key;
00575         return m->val;
00576 }
00577 
00578 /** Set the current element's value to a string.
00579  * This sets the current element's value to an string. The map must have been created
00580  * to hold int64s using <i>_stp_map_new(xxx, STRING)</i>
00581  *
00582  * If the element doesn't exist, it is created.  If no current element (key)
00583  * is set for the map, this function does nothing.
00584  * @param map
00585  * @param val new string
00586  */
00587 
00588 void _stp_map_set_str(MAP map, char *val)
00589 {
00590         struct map_node_str *m;
00591 
00592         if (map == NULL)
00593                 return;
00594 
00595         if (map->create) {
00596                 if (val == NULL)
00597                         return;
00598 
00599                 if (map->maxnum) {
00600                         if (list_empty(&map->pool)) {
00601                                 if (map->no_wrap) {
00602                                         /* ERROR. FIXME */
00603                                         return;
00604                                 }
00605                                 m = (struct map_node_str *)map->head.next;
00606                                 hlist_del_init(&m->n.hnode);
00607                                 map_free_strings(map, (struct map_node *)m);
00608                                 dbug ("got %lx off head\n", (long)m);
00609                         } else {
00610                                 m = (struct map_node_str *)map->pool.next;
00611                                 dbug ("got %lx off pool\n", (long)m);
00612                         }
00613                         list_move_tail(&m->n.lnode, &map->head);
00614                 } else {
00615                         m = (struct map_node_str *)
00616                             _stp_calloc(sizeof(struct map_node_str));
00617                         /* add node to list */
00618                         list_add_tail(&m->n.lnode, &map->head);
00619                 }
00620 
00621                 /* copy the key(s) */
00622                 map_copy_keys(map, &m->n);
00623 
00624                 /* set the value */
00625                 m->str = _stp_alloc(strlen(val) + 1);
00626                 strcpy(m->str, val);
00627         } else {
00628                 if (map->key == NULL)
00629                         return;
00630 
00631                 if (val) {
00632                         m = (struct map_node_str *)map->key;
00633                         if (m->str)
00634                                 _stp_free(m->str);
00635                         m->str = _stp_alloc(strlen(val) + 1);
00636                         strcpy(m->str, val);
00637                 } else {
00638                         /* setting value to 0 is the same as deleting */
00639                         _stp_map_key_del(map);
00640                 }
00641         }
00642 }
00643 
00644 /** Gets the current element's value.
00645  * @param map
00646  * @returns A string pointer. If the current element is not set or doesn't exist, returns NULL.
00647  */
00648 
00649 char *_stp_map_get_str(MAP map)
00650 {
00651         struct map_node_str *m;
00652         if (map == NULL || map->create || map->key == NULL)
00653                 return NULL;
00654         dbug ("%lx\n", (long)map->key);
00655         m = (struct map_node_str *)map->key;
00656         return m->str;
00657 }
00658 
00659 /** Set the current element's value to a stat.
00660  * This sets the current element's value to an stat struct. The map must have been created
00661  * to hold stats using <i>_stp_map_new(xxx, STAT)</i>.  This function would only be used
00662  * if we wanted to set stats to something other than the normal initial values (count = 0,
00663  * sum = 0, etc).  It may be deleted if it doesn't turn out to be useful.
00664  * @sa _stp_map_stat_add 
00665  *
00666  * If the element doesn't exist, it is created.  If no current element (key)
00667  * is set for the map, this function does nothing.
00668  * @param map
00669  * @param stats pointer to stats struct.
00670  * @todo Histograms don't work yet.
00671  */
00672 
00673 void _stp_map_set_stat(MAP map, stat * stats)
00674 {
00675         struct map_node_stat *m;
00676 
00677         if (map == NULL)
00678                 return;
00679         dbug ("set_stat %lx\n", (long)map->key);
00680 
00681         if (map->create) {
00682                 if (stats == NULL)
00683                         return;
00684 
00685                 if (map->maxnum) {
00686                         if (list_empty(&map->pool)) {
00687                                 if (map->no_wrap) {
00688                                         /* ERROR. FIXME */
00689                                         return;
00690                                 }
00691                                 m = (struct map_node_stat *)map->head.next;
00692                                 hlist_del_init(&m->n.hnode);
00693                                 map_free_strings(map, (struct map_node *)m);
00694                                 dbug ("got %lx off head\n", (long)m);
00695                         } else {
00696                                 m = (struct map_node_stat *)map->pool.next;
00697                                 dbug ("got %lx off pool\n", (long)m);
00698                         }
00699                         list_move_tail(&m->n.lnode, &map->head);
00700                 } else {
00701                         m = (struct map_node_stat *)
00702                             _stp_calloc(sizeof(struct map_node_stat));
00703                         /* add node to list */
00704                         list_add_tail(&m->n.lnode, &map->head);
00705                 }
00706 
00707                 /* copy the key(s) */
00708                 map_copy_keys(map, &m->n);
00709 
00710                 /* set the value */
00711                 memcpy(&m->stats, stats, sizeof(stat));
00712         } else {
00713                 if (map->key == NULL)
00714                         return;
00715 
00716                 if (stats) {
00717                         m = (struct map_node_stat *)map->key;
00718                         memcpy(&m->stats, stats, sizeof(stat));
00719                 } else {
00720                         /* setting value to NULL is the same as deleting */
00721                         _stp_map_key_del(map);
00722                 }
00723         }
00724 }
00725 
00726 /** Gets the current element's value.
00727  * @param map
00728  * @returns A pointer to the stats struct. If the current element is not set 
00729  * or doesn't exist, returns NULL.
00730  */
00731 
00732 stat *_stp_map_get_stat(MAP map)
00733 {
00734         struct map_node_stat *m;
00735         if (map == NULL || map->create || map->key == NULL)
00736                 return NULL;
00737         dbug ("%lx\n", (long)map->key);
00738         m = (struct map_node_stat *)map->key;
00739         return &m->stats;
00740 }
00741 
00742 /** Add to the current element's statistics.
00743  * Increments the statistics counter by one and the sum by <i>val</i>.
00744  * Adjusts minimum, maximum, and histogram.
00745  *
00746  * If the element doesn't exist, it is created.  If no current element (key)
00747  * is set for the map, this function does nothing.
00748  * @param map
00749  * @param val value to add to the statistics
00750  * @todo Histograms don't work yet.
00751  */
00752 
00753 void _stp_map_stat_add(MAP map, int64_t val)
00754 {
00755         struct map_node_stat *m;
00756         if (map == NULL)
00757                 return;
00758 
00759         if (map->create) {
00760                 stat st = { 1, val, val, val };
00761                 /* histogram */
00762                 _stp_map_set_stat(map, &st);
00763                 return;
00764         }
00765 
00766         if (map->key == NULL)
00767                 return;
00768 
00769         dbug ("add_stat %lx\n", (long)map->key);
00770         m = (struct map_node_stat *)map->key;
00771         m->stats.count++;
00772         m->stats.sum += val;
00773         if (val > m->stats.max)
00774                 m->stats.max = val;
00775         if (val < m->stats.min)
00776                 m->stats.min = val;
00777         /* histogram */
00778 }
00779 
00780 /** @} */
00781 
00782 /**********************  List Functions *********************/
00783 
00784 /** @addtogroup lists
00785  * Lists are special cases of maps.
00786  * @b Example:
00787  * @include list.c
00788  * @{ */
00789 
00790 /** Create a new list.
00791  * A list is a map that internally has an incrementing long key for each member.
00792  * Lists do not wrap if elements are added to exceed their maximum size.
00793  * @param max_entries The maximum number of entries allowed. Currently that number will
00794  * be preallocated.  If max_entries is 0, there will be no maximum and entries
00795  * will be allocated dynamically.
00796  * @param type Type of values stored in this list. 
00797  * @return A MAP on success or NULL on failure.
00798  * @sa foreach
00799  */
00800 
00801 MAP _stp_list_new(unsigned max_entries, enum valtype type)
00802 {
00803   MAP map = _stp_map_new (max_entries, type);
00804   map->no_wrap = 1;
00805   return map;
00806 }
00807 
00808 /** Clears a list.
00809  * All elements in the list are deleted.
00810  * @param map 
00811  */
00812 
00813 void _stp_list_clear(MAP map)
00814 {
00815         if (map == NULL)
00816                 return;
00817 
00818         if (!list_empty(&map->head)) {
00819                 struct map_node *ptr = (struct map_node *)map->head.next;
00820 
00821                 while (ptr && ptr != (struct map_node *)&map->head) {
00822                         struct map_node *next = (struct map_node *)ptr->lnode.next;
00823 
00824                         /* remove node from old hash list */
00825                         hlist_del_init(&ptr->hnode);
00826 
00827                         /* remove from entry list */
00828                         list_del(&ptr->lnode);
00829                         
00830                         /* remove any allocated string storage */
00831                         map_free_strings(map, ptr);
00832                         
00833                         if (map->maxnum)
00834                                 list_add(&ptr->lnode, &map->pool);
00835                         else
00836                                 _stp_free(ptr);
00837 
00838                         map->num--;
00839                         ptr = next;
00840                 }
00841         }
00842 
00843         if (map->num != 0) {
00844                 dlog ("ERROR: list is supposed to be empty (has %d)\n", map->num);
00845         }
00846 }
00847 
00848 /** Adds a string to a list.
00849  * @param map
00850  * @param str
00851  */
00852 
00853 inline void _stp_list_add_str(MAP map, char *str)
00854 {
00855         _stp_map_key_long(map, map->num);
00856         _stp_map_set_str(map, str);
00857 }
00858 
00859 /** Adds an int64 to a list.
00860  * @param map
00861  * @param val
00862  */
00863 
00864 inline void _stp_list_add_int64(MAP map, int64_t val)
00865 {
00866         _stp_map_key_long(map, map->num);
00867         _stp_map_set_int64(map, val);
00868 }
00869 
00870 /** Get the number of elements in a list.
00871  * @param map
00872  * @returns The number of elements in a list.
00873  */
00874 
00875 inline int _stp_list_size(MAP map)
00876 {
00877         return map->num;
00878 }
00879 /** @} */
00880 #endif /* _MAP_C_ */