2 * Copyright (c) 1984 through 2008, William LeFebvre
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
16 * * Neither the name of William LeFebvre nor the names of other
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 /* The file hash.c is generated from hash.m4c via the preprocessor M4 */
38 * Hash table functions: init, add, lookup, first, next, sizeinfo.
39 * This is a conventional "bucket hash". The key is hashed in to a number
40 * less than or equal to the number of buckets and the result is used
41 * to index in to the array of buckets. Each bucket is a linked list
42 * that contains all the key/value pairs which hashed to that index.
66 if ((i
/j
)==floor(i
/j
))
83 string_hash(hash_table
*ht
, char *key
)
90 while ((ch
= (unsigned char)*key
++) != '\0')
99 s
= s
+ (ch
<< shifting
);
104 return (s
% ht
->num_buckets
);
107 static void ll_init(llist
*q
)
114 static llistitem
*ll_newitem(int size
)
119 qi
= emalloc(sizeof(llistitem
) + size
);
120 qi
->datum
= ((char *)qi
+ sizeof(llistitem
));
124 static void ll_freeitem(llistitem
*li
)
130 static void ll_add(llist
*q
, llistitem
*new)
138 static void ll_extract(llist
*q
, llistitem
*qi
, llistitem
*last
)
147 last
->next
= qi
->next
;
153 #define LL_FIRST(q) ((q)->head)
154 #define LL_NEXT(q, qi) ((qi) != NULL ? (qi)->next : NULL)
155 #define LL_ISEMPTY(ll) ((ll)->count == 0)
166 ll_next(llist
*q
, llistitem
*qi
)
169 return (qi
!= NULL
? qi
->next
: NULL
);
173 ll_isempty(llist
*ll
)
176 return (ll
->count
== 0);
181 * hash_table *hash_create(int num)
183 * Creates a hash table structure with at least "num" buckets.
195 /* create the resultant structure */
196 result
= emalloc(sizeof(hash_table
));
198 /* adjust bucket count to be prime */
199 num
= next_prime(num
);
201 /* create the buckets */
202 bytes
= sizeof(bucket_t
) * num
;
203 result
->buckets
= b
= emalloc(bytes
);
204 result
->num_buckets
= num
;
206 /* create each bucket as a linked list */
218 * unsigned int hash_count(hash_table *ht)
220 * Return total number of elements contained in hash table.
225 hash_count(hash_table
*ht
)
229 register int cnt
= 0;
230 register bucket_t
*bucket
;
232 bucket
= ht
->buckets
;
233 while (i
++ < ht
->num_buckets
)
235 cnt
+= bucket
->list
.count
;
244 * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
246 * Fill in "sizes" with information about bucket lengths in hash
251 hash_sizeinfo(unsigned int *sizes
, int max
, hash_table
*ht
)
256 register bucket_t
*bucket
;
258 memzero(sizes
, max
* sizeof(unsigned int));
260 bucket
= ht
->buckets
;
262 while (i
++ < ht
->num_buckets
)
264 idx
= bucket
->list
.count
;
265 sizes
[idx
>= max
? max
-1 : idx
]++;
277 * void hash_add_uint(hash_table *ht, unsigned int key, void *value)
279 * Add an element to table "ht". The element is described by
280 * "key" and "value". Return NULL on success. If the key
281 * already exists in the table, then no action is taken and
282 * the data for the existing element is returned.
283 * Key type is unsigned int
287 hash_add_uint(hash_table
*ht
, unsigned int key
, void *value
)
298 /* allocate the space we will need */
299 newli
= ll_newitem(sizeof(hash_item_uint
));
300 hi
= (hash_item_uint
*)newli
->datum
;
302 /* fill in the values */
306 /* hash to the bucket */
307 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
309 /* walk the list to make sure we do not have a duplicate */
310 ll
= &(bucket
->list
);
314 h
= (hash_item_uint
*)li
->datum
;
321 li
= LL_NEXT(ll
, li
);
325 /* is there already one there? */
328 /* add the unique element to the buckets list */
329 ll_add(&(bucket
->list
), newli
);
334 /* free the stuff we just allocated */
336 return ((hash_item_uint
*)(li
->datum
))->value
;
341 * void *hash_replace_uint(hash_table *ht, unsigned int key, void *value)
343 * Replace an existing value in the hash table with a new one and
344 * return the old value. If the key does not already exist in
345 * the hash table, add a new element and return NULL.
346 * Key type is unsigned int
350 hash_replace_uint(hash_table
*ht
, unsigned int key
, void *value
)
360 /* find the bucket */
361 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
363 /* walk the list until we find the existing item */
364 ll
= &(bucket
->list
);
368 hi
= (hash_item_uint
*)li
->datum
;
372 /* found it: now replace the value with the new one */
377 li
= LL_NEXT(ll
, li
);
380 /* if the element wasnt found, add it */
383 li
= ll_newitem(sizeof(hash_item_uint
));
384 hi
= (hash_item_uint
*)li
->datum
;
387 ll_add(&(bucket
->list
), li
);
390 /* return the old value (so it can be freed) */
395 * void *hash_lookup_uint(hash_table *ht, unsigned int key)
397 * Look up "key" in "ht" and return the associated value. If "key"
398 * is not found, return NULL. Key type is unsigned int
402 hash_lookup_uint(hash_table
*ht
, unsigned int key
)
413 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
415 ll
= &(bucket
->list
);
419 h
= (hash_item_uint
*)li
->datum
;
426 li
= LL_NEXT(ll
, li
);
433 * void *hash_remove_uint(hash_table *ht, unsigned int key)
435 * Remove the element associated with "key" from the hash table
436 * "ht". Return the value or NULL if the key was not found.
440 hash_remove_uint(hash_table
*ht
, unsigned int key
)
452 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
454 ll
= &(bucket
->list
);
459 hi
= (hash_item_uint
*)li
->datum
;
463 ll_extract(ll
, li
, lilast
);
471 li
= LL_NEXT(ll
, li
);
478 * hash_item_uint *hash_first_uint(hash_table *ht, hash_pos *pos)
480 * First function to call when iterating through all items in the hash
481 * table. Returns the first item in "ht" and initializes "*pos" to track
482 * the current position.
486 hash_first_uint(hash_table
*ht
, hash_pos
*pos
)
489 /* initialize pos for first item in first bucket */
490 pos
->num_buckets
= ht
->num_buckets
;
491 pos
->hash_bucket
= ht
->buckets
;
495 /* find the first non-empty bucket */
496 while(pos
->hash_bucket
->list
.count
== 0)
499 if (++pos
->curr
>= pos
->num_buckets
)
505 /* set and return the first item */
506 pos
->ll_item
= LL_FIRST(&(pos
->hash_bucket
->list
));
507 return (hash_item_uint
*)pos
->ll_item
->datum
;
512 * hash_item_uint *hash_next_uint(hash_pos *pos)
514 * Return the next item in the hash table, using "pos" as a description
515 * of the present position in the hash table. "pos" also identifies the
516 * specific hash table. Return NULL if there are no more elements.
520 hash_next_uint(hash_pos
*pos
)
525 /* move item to last and check for NULL */
526 if ((pos
->ll_last
= pos
->ll_item
) == NULL
)
528 /* are we really at the end of the hash table? */
529 if (pos
->curr
>= pos
->num_buckets
)
531 /* yes: return NULL */
534 /* no: regrab first item in current bucket list (might be NULL) */
535 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
539 /* get the next item in the llist */
540 li
= LL_NEXT(&(pos
->hash_bucket
->list
), pos
->ll_item
);
543 /* if its NULL we have to find another bucket */
546 /* locate another bucket */
549 /* move to the next one */
551 if (++pos
->curr
>= pos
->num_buckets
)
553 /* at the end of the hash table */
558 /* get the first element (might be NULL) */
559 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
562 /* li is the next element to dish out */
564 return (hash_item_uint
*)li
->datum
;
568 * void *hash_remove_pos_uint(hash_pos *pos)
570 * Remove the hash table entry pointed to by position marker "pos".
571 * The data from the entry is returned upon success, otherwise NULL.
576 hash_remove_pos_uint(hash_pos
*pos
)
585 if (pos
== NULL
|| pos
->ll_last
== pos
->ll_item
)
590 /* at this point pos contains the item to remove (ll_item)
591 and its predecesor (ll_last) */
592 /* extract the item from the llist */
594 ll_extract(&(pos
->hash_bucket
->list
), li
, pos
->ll_last
);
596 /* retain the data */
597 hi
= (hash_item_uint
*)li
->datum
;
600 /* free up the space */
605 /* back up to previous item */
606 /* its okay for ll_item to be null: hash_next will detect it */
607 pos
->ll_item
= pos
->ll_last
;
615 * void hash_add_pid(hash_table *ht, pid_t key, void *value)
617 * Add an element to table "ht". The element is described by
618 * "key" and "value". Return NULL on success. If the key
619 * already exists in the table, then no action is taken and
620 * the data for the existing element is returned.
625 hash_add_pid(hash_table
*ht
, pid_t key
, void *value
)
636 /* allocate the space we will need */
637 newli
= ll_newitem(sizeof(hash_item_pid
));
638 hi
= (hash_item_pid
*)newli
->datum
;
640 /* fill in the values */
644 /* hash to the bucket */
645 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
647 /* walk the list to make sure we do not have a duplicate */
648 ll
= &(bucket
->list
);
652 h
= (hash_item_pid
*)li
->datum
;
659 li
= LL_NEXT(ll
, li
);
663 /* is there already one there? */
666 /* add the unique element to the buckets list */
667 ll_add(&(bucket
->list
), newli
);
672 /* free the stuff we just allocated */
674 return ((hash_item_pid
*)(li
->datum
))->value
;
679 * void *hash_replace_pid(hash_table *ht, pid_t key, void *value)
681 * Replace an existing value in the hash table with a new one and
682 * return the old value. If the key does not already exist in
683 * the hash table, add a new element and return NULL.
688 hash_replace_pid(hash_table
*ht
, pid_t key
, void *value
)
698 /* find the bucket */
699 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
701 /* walk the list until we find the existing item */
702 ll
= &(bucket
->list
);
706 hi
= (hash_item_pid
*)li
->datum
;
710 /* found it: now replace the value with the new one */
715 li
= LL_NEXT(ll
, li
);
718 /* if the element wasnt found, add it */
721 li
= ll_newitem(sizeof(hash_item_pid
));
722 hi
= (hash_item_pid
*)li
->datum
;
725 ll_add(&(bucket
->list
), li
);
728 /* return the old value (so it can be freed) */
733 * void *hash_lookup_pid(hash_table *ht, pid_t key)
735 * Look up "key" in "ht" and return the associated value. If "key"
736 * is not found, return NULL. Key type is pid_t
740 hash_lookup_pid(hash_table
*ht
, pid_t key
)
751 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
753 ll
= &(bucket
->list
);
757 h
= (hash_item_pid
*)li
->datum
;
764 li
= LL_NEXT(ll
, li
);
771 * void *hash_remove_pid(hash_table *ht, pid_t key)
773 * Remove the element associated with "key" from the hash table
774 * "ht". Return the value or NULL if the key was not found.
778 hash_remove_pid(hash_table
*ht
, pid_t key
)
790 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
792 ll
= &(bucket
->list
);
797 hi
= (hash_item_pid
*)li
->datum
;
801 ll_extract(ll
, li
, lilast
);
809 li
= LL_NEXT(ll
, li
);
816 * hash_item_pid *hash_first_pid(hash_table *ht, hash_pos *pos)
818 * First function to call when iterating through all items in the hash
819 * table. Returns the first item in "ht" and initializes "*pos" to track
820 * the current position.
824 hash_first_pid(hash_table
*ht
, hash_pos
*pos
)
827 /* initialize pos for first item in first bucket */
828 pos
->num_buckets
= ht
->num_buckets
;
829 pos
->hash_bucket
= ht
->buckets
;
833 /* find the first non-empty bucket */
834 while(pos
->hash_bucket
->list
.count
== 0)
837 if (++pos
->curr
>= pos
->num_buckets
)
843 /* set and return the first item */
844 pos
->ll_item
= LL_FIRST(&(pos
->hash_bucket
->list
));
845 return (hash_item_pid
*)pos
->ll_item
->datum
;
850 * hash_item_pid *hash_next_pid(hash_pos *pos)
852 * Return the next item in the hash table, using "pos" as a description
853 * of the present position in the hash table. "pos" also identifies the
854 * specific hash table. Return NULL if there are no more elements.
858 hash_next_pid(hash_pos
*pos
)
863 /* move item to last and check for NULL */
864 if ((pos
->ll_last
= pos
->ll_item
) == NULL
)
866 /* are we really at the end of the hash table? */
867 if (pos
->curr
>= pos
->num_buckets
)
869 /* yes: return NULL */
872 /* no: regrab first item in current bucket list (might be NULL) */
873 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
877 /* get the next item in the llist */
878 li
= LL_NEXT(&(pos
->hash_bucket
->list
), pos
->ll_item
);
881 /* if its NULL we have to find another bucket */
884 /* locate another bucket */
887 /* move to the next one */
889 if (++pos
->curr
>= pos
->num_buckets
)
891 /* at the end of the hash table */
896 /* get the first element (might be NULL) */
897 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
900 /* li is the next element to dish out */
902 return (hash_item_pid
*)li
->datum
;
906 * void *hash_remove_pos_pid(hash_pos *pos)
908 * Remove the hash table entry pointed to by position marker "pos".
909 * The data from the entry is returned upon success, otherwise NULL.
914 hash_remove_pos_pid(hash_pos
*pos
)
923 if (pos
== NULL
|| pos
->ll_last
== pos
->ll_item
)
928 /* at this point pos contains the item to remove (ll_item)
929 and its predecesor (ll_last) */
930 /* extract the item from the llist */
932 ll_extract(&(pos
->hash_bucket
->list
), li
, pos
->ll_last
);
934 /* retain the data */
935 hi
= (hash_item_pid
*)li
->datum
;
938 /* free up the space */
943 /* back up to previous item */
944 /* its okay for ll_item to be null: hash_next will detect it */
945 pos
->ll_item
= pos
->ll_last
;
953 * void hash_add_string(hash_table *ht, char * key, void *value)
955 * Add an element to table "ht". The element is described by
956 * "key" and "value". Return NULL on success. If the key
957 * already exists in the table, then no action is taken and
958 * the data for the existing element is returned.
963 hash_add_string(hash_table
*ht
, char * key
, void *value
)
967 hash_item_string
*hi
;
974 /* allocate the space we will need */
975 newli
= ll_newitem(sizeof(hash_item_string
));
976 hi
= (hash_item_string
*)newli
->datum
;
978 /* fill in the values */
979 hi
->key
= estrdup(key
);
982 /* hash to the bucket */
983 bucket
= &(ht
->buckets
[string_hash(ht
, key
)]);
985 /* walk the list to make sure we do not have a duplicate */
986 ll
= &(bucket
->list
);
990 h
= (hash_item_string
*)li
->datum
;
992 if (strcmp(key
, k1
) == 0)
997 li
= LL_NEXT(ll
, li
);
1001 /* is there already one there? */
1004 /* add the unique element to the buckets list */
1005 ll_add(&(bucket
->list
), newli
);
1010 /* free the stuff we just allocated */
1012 return ((hash_item_string
*)(li
->datum
))->value
;
1017 * void *hash_replace_string(hash_table *ht, char * key, void *value)
1019 * Replace an existing value in the hash table with a new one and
1020 * return the old value. If the key does not already exist in
1021 * the hash table, add a new element and return NULL.
1022 * Key type is char *
1026 hash_replace_string(hash_table
*ht
, char * key
, void *value
)
1030 hash_item_string
*hi
;
1033 void *result
= NULL
;
1036 /* find the bucket */
1037 bucket
= &(ht
->buckets
[string_hash(ht
, key
)]);
1039 /* walk the list until we find the existing item */
1040 ll
= &(bucket
->list
);
1044 hi
= (hash_item_string
*)li
->datum
;
1046 if (strcmp(key
, k1
) == 0)
1048 /* found it: now replace the value with the new one */
1053 li
= LL_NEXT(ll
, li
);
1056 /* if the element wasnt found, add it */
1059 li
= ll_newitem(sizeof(hash_item_string
));
1060 hi
= (hash_item_string
*)li
->datum
;
1061 hi
->key
= estrdup(key
);
1063 ll_add(&(bucket
->list
), li
);
1066 /* return the old value (so it can be freed) */
1071 * void *hash_lookup_string(hash_table *ht, char * key)
1073 * Look up "key" in "ht" and return the associated value. If "key"
1074 * is not found, return NULL. Key type is char *
1078 hash_lookup_string(hash_table
*ht
, char * key
)
1084 hash_item_string
*h
;
1089 if ((bucket
= &(ht
->buckets
[string_hash(ht
, key
)])) != NULL
)
1091 ll
= &(bucket
->list
);
1095 h
= (hash_item_string
*)li
->datum
;
1097 if (strcmp(key
, k1
) == 0)
1102 li
= LL_NEXT(ll
, li
);
1109 * void *hash_remove_string(hash_table *ht, char * key)
1111 * Remove the element associated with "key" from the hash table
1112 * "ht". Return the value or NULL if the key was not found.
1116 hash_remove_string(hash_table
*ht
, char * key
)
1123 hash_item_string
*hi
;
1128 if ((bucket
= &(ht
->buckets
[string_hash(ht
, key
)])) != NULL
)
1130 ll
= &(bucket
->list
);
1135 hi
= (hash_item_string
*)li
->datum
;
1137 if (strcmp(key
, k1
) == 0)
1139 ll_extract(ll
, li
, lilast
);
1147 li
= LL_NEXT(ll
, li
);
1154 * hash_item_string *hash_first_string(hash_table *ht, hash_pos *pos)
1156 * First function to call when iterating through all items in the hash
1157 * table. Returns the first item in "ht" and initializes "*pos" to track
1158 * the current position.
1162 hash_first_string(hash_table
*ht
, hash_pos
*pos
)
1165 /* initialize pos for first item in first bucket */
1166 pos
->num_buckets
= ht
->num_buckets
;
1167 pos
->hash_bucket
= ht
->buckets
;
1169 pos
->ll_last
= NULL
;
1171 /* find the first non-empty bucket */
1172 while(pos
->hash_bucket
->list
.count
== 0)
1175 if (++pos
->curr
>= pos
->num_buckets
)
1181 /* set and return the first item */
1182 pos
->ll_item
= LL_FIRST(&(pos
->hash_bucket
->list
));
1183 return (hash_item_string
*)pos
->ll_item
->datum
;
1188 * hash_item_string *hash_next_string(hash_pos *pos)
1190 * Return the next item in the hash table, using "pos" as a description
1191 * of the present position in the hash table. "pos" also identifies the
1192 * specific hash table. Return NULL if there are no more elements.
1196 hash_next_string(hash_pos
*pos
)
1201 /* move item to last and check for NULL */
1202 if ((pos
->ll_last
= pos
->ll_item
) == NULL
)
1204 /* are we really at the end of the hash table? */
1205 if (pos
->curr
>= pos
->num_buckets
)
1207 /* yes: return NULL */
1210 /* no: regrab first item in current bucket list (might be NULL) */
1211 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1215 /* get the next item in the llist */
1216 li
= LL_NEXT(&(pos
->hash_bucket
->list
), pos
->ll_item
);
1219 /* if its NULL we have to find another bucket */
1222 /* locate another bucket */
1223 pos
->ll_last
= NULL
;
1225 /* move to the next one */
1227 if (++pos
->curr
>= pos
->num_buckets
)
1229 /* at the end of the hash table */
1230 pos
->ll_item
= NULL
;
1234 /* get the first element (might be NULL) */
1235 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1238 /* li is the next element to dish out */
1240 return (hash_item_string
*)li
->datum
;
1244 * void *hash_remove_pos_string(hash_pos *pos)
1246 * Remove the hash table entry pointed to by position marker "pos".
1247 * The data from the entry is returned upon success, otherwise NULL.
1252 hash_remove_pos_string(hash_pos
*pos
)
1257 hash_item_string
*hi
;
1261 if (pos
== NULL
|| pos
->ll_last
== pos
->ll_item
)
1266 /* at this point pos contains the item to remove (ll_item)
1267 and its predecesor (ll_last) */
1268 /* extract the item from the llist */
1270 ll_extract(&(pos
->hash_bucket
->list
), li
, pos
->ll_last
);
1272 /* retain the data */
1273 hi
= (hash_item_string
*)li
->datum
;
1276 /* free up the space */
1281 /* back up to previous item */
1282 /* its okay for ll_item to be null: hash_next will detect it */
1283 pos
->ll_item
= pos
->ll_last
;
1291 * void hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1293 * Add an element to table "ht". The element is described by
1294 * "key" and "value". Return NULL on success. If the key
1295 * already exists in the table, then no action is taken and
1296 * the data for the existing element is returned.
1297 * Key type is pidthr_t
1301 hash_add_pidthr(hash_table
*ht
, pidthr_t key
, void *value
)
1305 hash_item_pidthr
*hi
;
1306 hash_item_pidthr
*h
;
1312 /* allocate the space we will need */
1313 newli
= ll_newitem(sizeof(hash_item_pidthr
));
1314 hi
= (hash_item_pidthr
*)newli
->datum
;
1316 /* fill in the values */
1320 /* hash to the bucket */
1321 bucket
= &(ht
->buckets
[((key
.k_thr
* 10000 + key
.k_pid
) % ht
->num_buckets
)]);
1323 /* walk the list to make sure we do not have a duplicate */
1324 ll
= &(bucket
->list
);
1328 h
= (hash_item_pidthr
*)li
->datum
;
1330 if ((key
.k_pid
== k1
.k_pid
&& key
.k_thr
== k1
.k_thr
))
1335 li
= LL_NEXT(ll
, li
);
1339 /* is there already one there? */
1342 /* add the unique element to the buckets list */
1343 ll_add(&(bucket
->list
), newli
);
1348 /* free the stuff we just allocated */
1350 return ((hash_item_pidthr
*)(li
->datum
))->value
;
1355 * void *hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1357 * Replace an existing value in the hash table with a new one and
1358 * return the old value. If the key does not already exist in
1359 * the hash table, add a new element and return NULL.
1360 * Key type is pidthr_t
1364 hash_replace_pidthr(hash_table
*ht
, pidthr_t key
, void *value
)
1368 hash_item_pidthr
*hi
;
1371 void *result
= NULL
;
1374 /* find the bucket */
1375 bucket
= &(ht
->buckets
[((key
.k_thr
* 10000 + key
.k_pid
) % ht
->num_buckets
)]);
1377 /* walk the list until we find the existing item */
1378 ll
= &(bucket
->list
);
1382 hi
= (hash_item_pidthr
*)li
->datum
;
1384 if ((key
.k_pid
== k1
.k_pid
&& key
.k_thr
== k1
.k_thr
))
1386 /* found it: now replace the value with the new one */
1391 li
= LL_NEXT(ll
, li
);
1394 /* if the element wasnt found, add it */
1397 li
= ll_newitem(sizeof(hash_item_pidthr
));
1398 hi
= (hash_item_pidthr
*)li
->datum
;
1401 ll_add(&(bucket
->list
), li
);
1404 /* return the old value (so it can be freed) */
1409 * void *hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1411 * Look up "key" in "ht" and return the associated value. If "key"
1412 * is not found, return NULL. Key type is pidthr_t
1416 hash_lookup_pidthr(hash_table
*ht
, pidthr_t key
)
1422 hash_item_pidthr
*h
;
1427 if ((bucket
= &(ht
->buckets
[((key
.k_thr
* 10000 + key
.k_pid
) % ht
->num_buckets
)])) != NULL
)
1429 ll
= &(bucket
->list
);
1433 h
= (hash_item_pidthr
*)li
->datum
;
1435 if ((key
.k_pid
== k1
.k_pid
&& key
.k_thr
== k1
.k_thr
))
1440 li
= LL_NEXT(ll
, li
);
1447 * void *hash_remove_pidthr(hash_table *ht, pidthr_t key)
1449 * Remove the element associated with "key" from the hash table
1450 * "ht". Return the value or NULL if the key was not found.
1454 hash_remove_pidthr(hash_table
*ht
, pidthr_t key
)
1461 hash_item_pidthr
*hi
;
1466 if ((bucket
= &(ht
->buckets
[((key
.k_thr
* 10000 + key
.k_pid
) % ht
->num_buckets
)])) != NULL
)
1468 ll
= &(bucket
->list
);
1473 hi
= (hash_item_pidthr
*)li
->datum
;
1475 if ((key
.k_pid
== k1
.k_pid
&& key
.k_thr
== k1
.k_thr
))
1477 ll_extract(ll
, li
, lilast
);
1485 li
= LL_NEXT(ll
, li
);
1492 * hash_item_pidthr *hash_first_pidthr(hash_table *ht, hash_pos *pos)
1494 * First function to call when iterating through all items in the hash
1495 * table. Returns the first item in "ht" and initializes "*pos" to track
1496 * the current position.
1500 hash_first_pidthr(hash_table
*ht
, hash_pos
*pos
)
1503 /* initialize pos for first item in first bucket */
1504 pos
->num_buckets
= ht
->num_buckets
;
1505 pos
->hash_bucket
= ht
->buckets
;
1507 pos
->ll_last
= NULL
;
1509 /* find the first non-empty bucket */
1510 while(pos
->hash_bucket
->list
.count
== 0)
1513 if (++pos
->curr
>= pos
->num_buckets
)
1519 /* set and return the first item */
1520 pos
->ll_item
= LL_FIRST(&(pos
->hash_bucket
->list
));
1521 return (hash_item_pidthr
*)pos
->ll_item
->datum
;
1526 * hash_item_pidthr *hash_next_pidthr(hash_pos *pos)
1528 * Return the next item in the hash table, using "pos" as a description
1529 * of the present position in the hash table. "pos" also identifies the
1530 * specific hash table. Return NULL if there are no more elements.
1534 hash_next_pidthr(hash_pos
*pos
)
1539 /* move item to last and check for NULL */
1540 if ((pos
->ll_last
= pos
->ll_item
) == NULL
)
1542 /* are we really at the end of the hash table? */
1543 if (pos
->curr
>= pos
->num_buckets
)
1545 /* yes: return NULL */
1548 /* no: regrab first item in current bucket list (might be NULL) */
1549 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1553 /* get the next item in the llist */
1554 li
= LL_NEXT(&(pos
->hash_bucket
->list
), pos
->ll_item
);
1557 /* if its NULL we have to find another bucket */
1560 /* locate another bucket */
1561 pos
->ll_last
= NULL
;
1563 /* move to the next one */
1565 if (++pos
->curr
>= pos
->num_buckets
)
1567 /* at the end of the hash table */
1568 pos
->ll_item
= NULL
;
1572 /* get the first element (might be NULL) */
1573 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1576 /* li is the next element to dish out */
1578 return (hash_item_pidthr
*)li
->datum
;
1582 * void *hash_remove_pos_pidthr(hash_pos *pos)
1584 * Remove the hash table entry pointed to by position marker "pos".
1585 * The data from the entry is returned upon success, otherwise NULL.
1590 hash_remove_pos_pidthr(hash_pos
*pos
)
1595 hash_item_pidthr
*hi
;
1599 if (pos
== NULL
|| pos
->ll_last
== pos
->ll_item
)
1604 /* at this point pos contains the item to remove (ll_item)
1605 and its predecesor (ll_last) */
1606 /* extract the item from the llist */
1608 ll_extract(&(pos
->hash_bucket
->list
), li
, pos
->ll_last
);
1610 /* retain the data */
1611 hi
= (hash_item_pidthr
*)li
->datum
;
1614 /* free up the space */
1619 /* back up to previous item */
1620 /* its okay for ll_item to be null: hash_next will detect it */
1621 pos
->ll_item
= pos
->ll_last
;
1630 * void hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1632 * Add an element to table "ht". The element is described by
1633 * "key" and "value". Return NULL on success. If the key
1634 * already exists in the table, then no action is taken and
1635 * the data for the existing element is returned.
1636 * Key type is lwpid_t
1640 hash_add_lwpid(hash_table
*ht
, lwpid_t key
, void *value
)
1644 hash_item_lwpid
*hi
;
1651 /* allocate the space we will need */
1652 newli
= ll_newitem(sizeof(hash_item_lwpid
));
1653 hi
= (hash_item_lwpid
*)newli
->datum
;
1655 /* fill in the values */
1659 /* hash to the bucket */
1660 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
1662 /* walk the list to make sure we do not have a duplicate */
1663 ll
= &(bucket
->list
);
1667 h
= (hash_item_lwpid
*)li
->datum
;
1674 li
= LL_NEXT(ll
, li
);
1678 /* is there already one there? */
1681 /* add the unique element to the buckets list */
1682 ll_add(&(bucket
->list
), newli
);
1687 /* free the stuff we just allocated */
1689 return ((hash_item_lwpid
*)(li
->datum
))->value
;
1694 * void *hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1696 * Replace an existing value in the hash table with a new one and
1697 * return the old value. If the key does not already exist in
1698 * the hash table, add a new element and return NULL.
1699 * Key type is lwpid_t
1703 hash_replace_lwpid(hash_table
*ht
, lwpid_t key
, void *value
)
1707 hash_item_lwpid
*hi
;
1710 void *result
= NULL
;
1713 /* find the bucket */
1714 bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)]);
1716 /* walk the list until we find the existing item */
1717 ll
= &(bucket
->list
);
1721 hi
= (hash_item_lwpid
*)li
->datum
;
1725 /* found it: now replace the value with the new one */
1730 li
= LL_NEXT(ll
, li
);
1733 /* if the element wasnt found, add it */
1736 li
= ll_newitem(sizeof(hash_item_lwpid
));
1737 hi
= (hash_item_lwpid
*)li
->datum
;
1740 ll_add(&(bucket
->list
), li
);
1743 /* return the old value (so it can be freed) */
1748 * void *hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1750 * Look up "key" in "ht" and return the associated value. If "key"
1751 * is not found, return NULL. Key type is lwpid_t
1755 hash_lookup_lwpid(hash_table
*ht
, lwpid_t key
)
1766 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
1768 ll
= &(bucket
->list
);
1772 h
= (hash_item_lwpid
*)li
->datum
;
1779 li
= LL_NEXT(ll
, li
);
1786 * void *hash_remove_lwpid(hash_table *ht, lwpid_t key)
1788 * Remove the element associated with "key" from the hash table
1789 * "ht". Return the value or NULL if the key was not found.
1793 hash_remove_lwpid(hash_table
*ht
, lwpid_t key
)
1800 hash_item_lwpid
*hi
;
1805 if ((bucket
= &(ht
->buckets
[(key
% ht
->num_buckets
)])) != NULL
)
1807 ll
= &(bucket
->list
);
1812 hi
= (hash_item_lwpid
*)li
->datum
;
1816 ll_extract(ll
, li
, lilast
);
1824 li
= LL_NEXT(ll
, li
);
1831 * hash_item_lwpid *hash_first_lwpid(hash_table *ht, hash_pos *pos)
1833 * First function to call when iterating through all items in the hash
1834 * table. Returns the first item in "ht" and initializes "*pos" to track
1835 * the current position.
1839 hash_first_lwpid(hash_table
*ht
, hash_pos
*pos
)
1842 /* initialize pos for first item in first bucket */
1843 pos
->num_buckets
= ht
->num_buckets
;
1844 pos
->hash_bucket
= ht
->buckets
;
1846 pos
->ll_last
= NULL
;
1848 /* find the first non-empty bucket */
1849 while(pos
->hash_bucket
->list
.count
== 0)
1852 if (++pos
->curr
>= pos
->num_buckets
)
1858 /* set and return the first item */
1859 pos
->ll_item
= LL_FIRST(&(pos
->hash_bucket
->list
));
1860 return (hash_item_lwpid
*)pos
->ll_item
->datum
;
1865 * hash_item_lwpid *hash_next_lwpid(hash_pos *pos)
1867 * Return the next item in the hash table, using "pos" as a description
1868 * of the present position in the hash table. "pos" also identifies the
1869 * specific hash table. Return NULL if there are no more elements.
1873 hash_next_lwpid(hash_pos
*pos
)
1878 /* move item to last and check for NULL */
1879 if ((pos
->ll_last
= pos
->ll_item
) == NULL
)
1881 /* are we really at the end of the hash table? */
1882 if (pos
->curr
>= pos
->num_buckets
)
1884 /* yes: return NULL */
1887 /* no: regrab first item in current bucket list (might be NULL) */
1888 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1892 /* get the next item in the llist */
1893 li
= LL_NEXT(&(pos
->hash_bucket
->list
), pos
->ll_item
);
1896 /* if its NULL we have to find another bucket */
1899 /* locate another bucket */
1900 pos
->ll_last
= NULL
;
1902 /* move to the next one */
1904 if (++pos
->curr
>= pos
->num_buckets
)
1906 /* at the end of the hash table */
1907 pos
->ll_item
= NULL
;
1911 /* get the first element (might be NULL) */
1912 li
= LL_FIRST(&(pos
->hash_bucket
->list
));
1915 /* li is the next element to dish out */
1917 return (hash_item_lwpid
*)li
->datum
;
1921 * void *hash_remove_pos_lwpid(hash_pos *pos)
1923 * Remove the hash table entry pointed to by position marker "pos".
1924 * The data from the entry is returned upon success, otherwise NULL.
1929 hash_remove_pos_lwpid(hash_pos
*pos
)
1934 hash_item_lwpid
*hi
;
1938 if (pos
== NULL
|| pos
->ll_last
== pos
->ll_item
)
1943 /* at this point pos contains the item to remove (ll_item)
1944 and its predecesor (ll_last) */
1945 /* extract the item from the llist */
1947 ll_extract(&(pos
->hash_bucket
->list
), li
, pos
->ll_last
);
1949 /* retain the data */
1950 hi
= (hash_item_lwpid
*)li
->datum
;
1953 /* free up the space */
1958 /* back up to previous item */
1959 /* its okay for ll_item to be null: hash_next will detect it */
1960 pos
->ll_item
= pos
->ll_last
;