Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / top / dist / hash.c
blob4be1f462714985341e1f210790d3128322b7c922
1 /*
2 * Copyright (c) 1984 through 2008, William LeFebvre
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
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
14 * distribution.
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.
33 /* hash.m4c */
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.
45 #include "os.h"
47 #ifdef HAVE_MATH_H
48 #include <math.h>
49 #endif
51 #include "hash.h"
53 static int
54 next_prime(int x)
57 double i, j;
58 int f;
60 i = x;
61 while (i++)
63 f=1;
64 for (j=2; j<i; j++)
66 if ((i/j)==floor(i/j))
68 f=0;
69 break;
72 if (f)
74 return (int)i;
77 return 1;
80 /* string hashes */
82 static int
83 string_hash(hash_table *ht, char *key)
86 unsigned long s = 0;
87 unsigned char ch;
88 int shifting = 24;
90 while ((ch = (unsigned char)*key++) != '\0')
92 if (shifting == 0)
94 s = s + ch;
95 shifting = 24;
97 else
99 s = s + (ch << shifting);
100 shifting -= 8;
104 return (s % ht->num_buckets);
107 static void ll_init(llist *q)
110 q->head = NULL;
111 q->count = 0;
114 static llistitem *ll_newitem(int size)
117 llistitem *qi;
119 qi = emalloc(sizeof(llistitem) + size);
120 qi->datum = ((char *)qi + sizeof(llistitem));
121 return qi;
124 static void ll_freeitem(llistitem *li)
127 free(li);
130 static void ll_add(llist *q, llistitem *new)
133 new->next = q->head;
134 q->head = new;
135 q->count++;
138 static void ll_extract(llist *q, llistitem *qi, llistitem *last)
141 if (last == NULL)
143 q->head = qi->next;
145 else
147 last->next = qi->next;
149 qi->next = NULL;
150 q->count--;
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)
157 #ifdef notdef
158 static llistitem *
159 ll_first(llist *q)
162 return q->head;
165 static llistitem *
166 ll_next(llist *q, llistitem *qi)
169 return (qi != NULL ? qi->next : NULL);
172 static int
173 ll_isempty(llist *ll)
176 return (ll->count == 0);
178 #endif
181 * hash_table *hash_create(int num)
183 * Creates a hash table structure with at least "num" buckets.
186 hash_table *
187 hash_create(int num)
190 hash_table *result;
191 bucket_t *b;
192 int bytes;
193 int i;
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 */
207 i = num;
208 while (--i >= 0)
210 ll_init(&(b->list));
211 b++;
214 return result;
218 * unsigned int hash_count(hash_table *ht)
220 * Return total number of elements contained in hash table.
223 #ifdef notdef
224 static unsigned int
225 hash_count(hash_table *ht)
228 register int i = 0;
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;
236 bucket++;
239 return cnt;
241 #endif
244 * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
246 * Fill in "sizes" with information about bucket lengths in hash
247 * table "max".
250 void
251 hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
254 register int i;
255 register int idx;
256 register bucket_t *bucket;
258 memzero(sizes, max * sizeof(unsigned int));
260 bucket = ht->buckets;
261 i = 0;
262 while (i++ < ht->num_buckets)
264 idx = bucket->list.count;
265 sizes[idx >= max ? max-1 : idx]++;
266 bucket++;
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
286 void *
287 hash_add_uint(hash_table *ht, unsigned int key, void *value)
290 bucket_t *bucket;
291 hash_item_uint *hi;
292 hash_item_uint *h;
293 llist *ll;
294 llistitem *li;
295 llistitem *newli;
296 unsigned int k1;
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 */
303 hi->key = key;
304 hi->value = value;
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);
311 li = LL_FIRST(ll);
312 while (li != NULL)
314 h = (hash_item_uint *)li->datum;
315 k1 = h->key;
316 if (key == k1)
318 /* found one */
319 break;
321 li = LL_NEXT(ll, li);
323 li = NULL;
325 /* is there already one there? */
326 if (li == NULL)
328 /* add the unique element to the buckets list */
329 ll_add(&(bucket->list), newli);
330 return NULL;
332 else
334 /* free the stuff we just allocated */
335 ll_freeitem(newli);
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
349 void *
350 hash_replace_uint(hash_table *ht, unsigned int key, void *value)
353 bucket_t *bucket;
354 hash_item_uint *hi;
355 llist *ll;
356 llistitem *li;
357 void *result = NULL;
358 unsigned int k1;
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);
365 li = LL_FIRST(ll);
366 while (li != NULL)
368 hi = (hash_item_uint *)li->datum;
369 k1 = hi->key;
370 if (key == k1)
372 /* found it: now replace the value with the new one */
373 result = hi->value;
374 hi->value = value;
375 break;
377 li = LL_NEXT(ll, li);
380 /* if the element wasnt found, add it */
381 if (result == NULL)
383 li = ll_newitem(sizeof(hash_item_uint));
384 hi = (hash_item_uint *)li->datum;
385 hi->key = key;
386 hi->value = value;
387 ll_add(&(bucket->list), li);
390 /* return the old value (so it can be freed) */
391 return result;
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
401 void *
402 hash_lookup_uint(hash_table *ht, unsigned int key)
405 bucket_t *bucket;
406 llist *ll;
407 llistitem *li;
408 hash_item_uint *h;
409 void *result;
410 unsigned int k1;
412 result = NULL;
413 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
415 ll = &(bucket->list);
416 li = LL_FIRST(ll);
417 while (li != NULL)
419 h = (hash_item_uint *)li->datum;
420 k1 = h->key;
421 if (key == k1)
423 result = h->value;
424 break;
426 li = LL_NEXT(ll, li);
429 return result;
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.
439 void *
440 hash_remove_uint(hash_table *ht, unsigned int key)
443 bucket_t *bucket;
444 llist *ll;
445 llistitem *li;
446 llistitem *lilast;
447 hash_item_uint *hi;
448 void *result;
449 unsigned int k1;
451 result = NULL;
452 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
454 ll = &(bucket->list);
455 li = LL_FIRST(ll);
456 lilast = NULL;
457 while (li != NULL)
459 hi = (hash_item_uint *)li->datum;
460 k1 = hi->key;
461 if (key == k1)
463 ll_extract(ll, li, lilast);
464 result = hi->value;
465 key = hi->key;
467 ll_freeitem(li);
468 break;
470 lilast = li;
471 li = LL_NEXT(ll, li);
474 return result;
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.
485 hash_item_uint *
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;
492 pos->curr = 0;
493 pos->ll_last = NULL;
495 /* find the first non-empty bucket */
496 while(pos->hash_bucket->list.count == 0)
498 pos->hash_bucket++;
499 if (++pos->curr >= pos->num_buckets)
501 return NULL;
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.
519 hash_item_uint *
520 hash_next_uint(hash_pos *pos)
523 llistitem *li;
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 */
532 return NULL;
534 /* no: regrab first item in current bucket list (might be NULL) */
535 li = LL_FIRST(&(pos->hash_bucket->list));
537 else
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 */
544 while (li == NULL)
546 /* locate another bucket */
547 pos->ll_last = NULL;
549 /* move to the next one */
550 pos->hash_bucket++;
551 if (++pos->curr >= pos->num_buckets)
553 /* at the end of the hash table */
554 pos->ll_item = NULL;
555 return NULL;
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 */
563 pos->ll_item = li;
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.
575 void *
576 hash_remove_pos_uint(hash_pos *pos)
579 llistitem *li;
580 void *ans;
581 hash_item_uint *hi;
582 unsigned int key;
584 /* sanity checks */
585 if (pos == NULL || pos->ll_last == pos->ll_item)
587 return NULL;
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 */
593 li = pos->ll_item;
594 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
596 /* retain the data */
597 hi = (hash_item_uint *)li->datum;
598 ans = hi->value;
600 /* free up the space */
601 key = hi->key;
603 ll_freeitem(li);
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;
609 return ans;
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.
621 * Key type is pid_t
624 void *
625 hash_add_pid(hash_table *ht, pid_t key, void *value)
628 bucket_t *bucket;
629 hash_item_pid *hi;
630 hash_item_pid *h;
631 llist *ll;
632 llistitem *li;
633 llistitem *newli;
634 pid_t k1;
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 */
641 hi->key = key;
642 hi->value = value;
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);
649 li = LL_FIRST(ll);
650 while (li != NULL)
652 h = (hash_item_pid *)li->datum;
653 k1 = h->key;
654 if (key == k1)
656 /* found one */
657 break;
659 li = LL_NEXT(ll, li);
661 li = NULL;
663 /* is there already one there? */
664 if (li == NULL)
666 /* add the unique element to the buckets list */
667 ll_add(&(bucket->list), newli);
668 return NULL;
670 else
672 /* free the stuff we just allocated */
673 ll_freeitem(newli);
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.
684 * Key type is pid_t
687 void *
688 hash_replace_pid(hash_table *ht, pid_t key, void *value)
691 bucket_t *bucket;
692 hash_item_pid *hi;
693 llist *ll;
694 llistitem *li;
695 void *result = NULL;
696 pid_t k1;
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);
703 li = LL_FIRST(ll);
704 while (li != NULL)
706 hi = (hash_item_pid *)li->datum;
707 k1 = hi->key;
708 if (key == k1)
710 /* found it: now replace the value with the new one */
711 result = hi->value;
712 hi->value = value;
713 break;
715 li = LL_NEXT(ll, li);
718 /* if the element wasnt found, add it */
719 if (result == NULL)
721 li = ll_newitem(sizeof(hash_item_pid));
722 hi = (hash_item_pid *)li->datum;
723 hi->key = key;
724 hi->value = value;
725 ll_add(&(bucket->list), li);
728 /* return the old value (so it can be freed) */
729 return result;
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
739 void *
740 hash_lookup_pid(hash_table *ht, pid_t key)
743 bucket_t *bucket;
744 llist *ll;
745 llistitem *li;
746 hash_item_pid *h;
747 void *result;
748 pid_t k1;
750 result = NULL;
751 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
753 ll = &(bucket->list);
754 li = LL_FIRST(ll);
755 while (li != NULL)
757 h = (hash_item_pid *)li->datum;
758 k1 = h->key;
759 if (key == k1)
761 result = h->value;
762 break;
764 li = LL_NEXT(ll, li);
767 return result;
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.
777 void *
778 hash_remove_pid(hash_table *ht, pid_t key)
781 bucket_t *bucket;
782 llist *ll;
783 llistitem *li;
784 llistitem *lilast;
785 hash_item_pid *hi;
786 void *result;
787 pid_t k1;
789 result = NULL;
790 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
792 ll = &(bucket->list);
793 li = LL_FIRST(ll);
794 lilast = NULL;
795 while (li != NULL)
797 hi = (hash_item_pid *)li->datum;
798 k1 = hi->key;
799 if (key == k1)
801 ll_extract(ll, li, lilast);
802 result = hi->value;
803 key = hi->key;
805 ll_freeitem(li);
806 break;
808 lilast = li;
809 li = LL_NEXT(ll, li);
812 return result;
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.
823 hash_item_pid *
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;
830 pos->curr = 0;
831 pos->ll_last = NULL;
833 /* find the first non-empty bucket */
834 while(pos->hash_bucket->list.count == 0)
836 pos->hash_bucket++;
837 if (++pos->curr >= pos->num_buckets)
839 return NULL;
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.
857 hash_item_pid *
858 hash_next_pid(hash_pos *pos)
861 llistitem *li;
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 */
870 return NULL;
872 /* no: regrab first item in current bucket list (might be NULL) */
873 li = LL_FIRST(&(pos->hash_bucket->list));
875 else
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 */
882 while (li == NULL)
884 /* locate another bucket */
885 pos->ll_last = NULL;
887 /* move to the next one */
888 pos->hash_bucket++;
889 if (++pos->curr >= pos->num_buckets)
891 /* at the end of the hash table */
892 pos->ll_item = NULL;
893 return NULL;
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 */
901 pos->ll_item = li;
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.
913 void *
914 hash_remove_pos_pid(hash_pos *pos)
917 llistitem *li;
918 void *ans;
919 hash_item_pid *hi;
920 pid_t key;
922 /* sanity checks */
923 if (pos == NULL || pos->ll_last == pos->ll_item)
925 return NULL;
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 */
931 li = pos->ll_item;
932 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
934 /* retain the data */
935 hi = (hash_item_pid *)li->datum;
936 ans = hi->value;
938 /* free up the space */
939 key = hi->key;
941 ll_freeitem(li);
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;
947 return ans;
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.
959 * Key type is char *
962 void *
963 hash_add_string(hash_table *ht, char * key, void *value)
966 bucket_t *bucket;
967 hash_item_string *hi;
968 hash_item_string *h;
969 llist *ll;
970 llistitem *li;
971 llistitem *newli;
972 char * k1;
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);
980 hi->value = value;
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);
987 li = LL_FIRST(ll);
988 while (li != NULL)
990 h = (hash_item_string *)li->datum;
991 k1 = h->key;
992 if (strcmp(key, k1) == 0)
994 /* found one */
995 break;
997 li = LL_NEXT(ll, li);
999 li = NULL;
1001 /* is there already one there? */
1002 if (li == NULL)
1004 /* add the unique element to the buckets list */
1005 ll_add(&(bucket->list), newli);
1006 return NULL;
1008 else
1010 /* free the stuff we just allocated */
1011 ll_freeitem(newli);
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 *
1025 void *
1026 hash_replace_string(hash_table *ht, char * key, void *value)
1029 bucket_t *bucket;
1030 hash_item_string *hi;
1031 llist *ll;
1032 llistitem *li;
1033 void *result = NULL;
1034 char * k1;
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);
1041 li = LL_FIRST(ll);
1042 while (li != NULL)
1044 hi = (hash_item_string *)li->datum;
1045 k1 = hi->key;
1046 if (strcmp(key, k1) == 0)
1048 /* found it: now replace the value with the new one */
1049 result = hi->value;
1050 hi->value = value;
1051 break;
1053 li = LL_NEXT(ll, li);
1056 /* if the element wasnt found, add it */
1057 if (result == NULL)
1059 li = ll_newitem(sizeof(hash_item_string));
1060 hi = (hash_item_string *)li->datum;
1061 hi->key = estrdup(key);
1062 hi->value = value;
1063 ll_add(&(bucket->list), li);
1066 /* return the old value (so it can be freed) */
1067 return result;
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 *
1077 void *
1078 hash_lookup_string(hash_table *ht, char * key)
1081 bucket_t *bucket;
1082 llist *ll;
1083 llistitem *li;
1084 hash_item_string *h;
1085 void *result;
1086 char * k1;
1088 result = NULL;
1089 if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1091 ll = &(bucket->list);
1092 li = LL_FIRST(ll);
1093 while (li != NULL)
1095 h = (hash_item_string *)li->datum;
1096 k1 = h->key;
1097 if (strcmp(key, k1) == 0)
1099 result = h->value;
1100 break;
1102 li = LL_NEXT(ll, li);
1105 return result;
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.
1115 void *
1116 hash_remove_string(hash_table *ht, char * key)
1119 bucket_t *bucket;
1120 llist *ll;
1121 llistitem *li;
1122 llistitem *lilast;
1123 hash_item_string *hi;
1124 void *result;
1125 char * k1;
1127 result = NULL;
1128 if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1130 ll = &(bucket->list);
1131 li = LL_FIRST(ll);
1132 lilast = NULL;
1133 while (li != NULL)
1135 hi = (hash_item_string *)li->datum;
1136 k1 = hi->key;
1137 if (strcmp(key, k1) == 0)
1139 ll_extract(ll, li, lilast);
1140 result = hi->value;
1141 key = hi->key;
1142 free(key);
1143 ll_freeitem(li);
1144 break;
1146 lilast = li;
1147 li = LL_NEXT(ll, li);
1150 return result;
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.
1161 hash_item_string *
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;
1168 pos->curr = 0;
1169 pos->ll_last = NULL;
1171 /* find the first non-empty bucket */
1172 while(pos->hash_bucket->list.count == 0)
1174 pos->hash_bucket++;
1175 if (++pos->curr >= pos->num_buckets)
1177 return NULL;
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.
1195 hash_item_string *
1196 hash_next_string(hash_pos *pos)
1199 llistitem *li;
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 */
1208 return NULL;
1210 /* no: regrab first item in current bucket list (might be NULL) */
1211 li = LL_FIRST(&(pos->hash_bucket->list));
1213 else
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 */
1220 while (li == NULL)
1222 /* locate another bucket */
1223 pos->ll_last = NULL;
1225 /* move to the next one */
1226 pos->hash_bucket++;
1227 if (++pos->curr >= pos->num_buckets)
1229 /* at the end of the hash table */
1230 pos->ll_item = NULL;
1231 return 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 */
1239 pos->ll_item = li;
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.
1251 void *
1252 hash_remove_pos_string(hash_pos *pos)
1255 llistitem *li;
1256 void *ans;
1257 hash_item_string *hi;
1258 char * key;
1260 /* sanity checks */
1261 if (pos == NULL || pos->ll_last == pos->ll_item)
1263 return NULL;
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 */
1269 li = pos->ll_item;
1270 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1272 /* retain the data */
1273 hi = (hash_item_string *)li->datum;
1274 ans = hi->value;
1276 /* free up the space */
1277 key = hi->key;
1278 free(key);
1279 ll_freeitem(li);
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;
1285 return ans;
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
1300 void *
1301 hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1304 bucket_t *bucket;
1305 hash_item_pidthr *hi;
1306 hash_item_pidthr *h;
1307 llist *ll;
1308 llistitem *li;
1309 llistitem *newli;
1310 pidthr_t k1;
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 */
1317 hi->key = key;
1318 hi->value = value;
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);
1325 li = LL_FIRST(ll);
1326 while (li != NULL)
1328 h = (hash_item_pidthr *)li->datum;
1329 k1 = h->key;
1330 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1332 /* found one */
1333 break;
1335 li = LL_NEXT(ll, li);
1337 li = NULL;
1339 /* is there already one there? */
1340 if (li == NULL)
1342 /* add the unique element to the buckets list */
1343 ll_add(&(bucket->list), newli);
1344 return NULL;
1346 else
1348 /* free the stuff we just allocated */
1349 ll_freeitem(newli);
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
1363 void *
1364 hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1367 bucket_t *bucket;
1368 hash_item_pidthr *hi;
1369 llist *ll;
1370 llistitem *li;
1371 void *result = NULL;
1372 pidthr_t k1;
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);
1379 li = LL_FIRST(ll);
1380 while (li != NULL)
1382 hi = (hash_item_pidthr *)li->datum;
1383 k1 = hi->key;
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 */
1387 result = hi->value;
1388 hi->value = value;
1389 break;
1391 li = LL_NEXT(ll, li);
1394 /* if the element wasnt found, add it */
1395 if (result == NULL)
1397 li = ll_newitem(sizeof(hash_item_pidthr));
1398 hi = (hash_item_pidthr *)li->datum;
1399 hi->key = key;
1400 hi->value = value;
1401 ll_add(&(bucket->list), li);
1404 /* return the old value (so it can be freed) */
1405 return result;
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
1415 void *
1416 hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1419 bucket_t *bucket;
1420 llist *ll;
1421 llistitem *li;
1422 hash_item_pidthr *h;
1423 void *result;
1424 pidthr_t k1;
1426 result = NULL;
1427 if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1429 ll = &(bucket->list);
1430 li = LL_FIRST(ll);
1431 while (li != NULL)
1433 h = (hash_item_pidthr *)li->datum;
1434 k1 = h->key;
1435 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1437 result = h->value;
1438 break;
1440 li = LL_NEXT(ll, li);
1443 return result;
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.
1453 void *
1454 hash_remove_pidthr(hash_table *ht, pidthr_t key)
1457 bucket_t *bucket;
1458 llist *ll;
1459 llistitem *li;
1460 llistitem *lilast;
1461 hash_item_pidthr *hi;
1462 void *result;
1463 pidthr_t k1;
1465 result = NULL;
1466 if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1468 ll = &(bucket->list);
1469 li = LL_FIRST(ll);
1470 lilast = NULL;
1471 while (li != NULL)
1473 hi = (hash_item_pidthr *)li->datum;
1474 k1 = hi->key;
1475 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1477 ll_extract(ll, li, lilast);
1478 result = hi->value;
1479 key = hi->key;
1481 ll_freeitem(li);
1482 break;
1484 lilast = li;
1485 li = LL_NEXT(ll, li);
1488 return result;
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.
1499 hash_item_pidthr *
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;
1506 pos->curr = 0;
1507 pos->ll_last = NULL;
1509 /* find the first non-empty bucket */
1510 while(pos->hash_bucket->list.count == 0)
1512 pos->hash_bucket++;
1513 if (++pos->curr >= pos->num_buckets)
1515 return NULL;
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.
1533 hash_item_pidthr *
1534 hash_next_pidthr(hash_pos *pos)
1537 llistitem *li;
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 */
1546 return NULL;
1548 /* no: regrab first item in current bucket list (might be NULL) */
1549 li = LL_FIRST(&(pos->hash_bucket->list));
1551 else
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 */
1558 while (li == NULL)
1560 /* locate another bucket */
1561 pos->ll_last = NULL;
1563 /* move to the next one */
1564 pos->hash_bucket++;
1565 if (++pos->curr >= pos->num_buckets)
1567 /* at the end of the hash table */
1568 pos->ll_item = NULL;
1569 return 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 */
1577 pos->ll_item = li;
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.
1589 void *
1590 hash_remove_pos_pidthr(hash_pos *pos)
1593 llistitem *li;
1594 void *ans;
1595 hash_item_pidthr *hi;
1596 pidthr_t key;
1598 /* sanity checks */
1599 if (pos == NULL || pos->ll_last == pos->ll_item)
1601 return NULL;
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 */
1607 li = pos->ll_item;
1608 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1610 /* retain the data */
1611 hi = (hash_item_pidthr *)li->datum;
1612 ans = hi->value;
1614 /* free up the space */
1615 key = hi->key;
1617 ll_freeitem(li);
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;
1623 return ans;
1626 #if HAVE_LWPID_T
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
1639 void *
1640 hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1643 bucket_t *bucket;
1644 hash_item_lwpid *hi;
1645 hash_item_lwpid *h;
1646 llist *ll;
1647 llistitem *li;
1648 llistitem *newli;
1649 lwpid_t k1;
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 */
1656 hi->key = key;
1657 hi->value = value;
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);
1664 li = LL_FIRST(ll);
1665 while (li != NULL)
1667 h = (hash_item_lwpid *)li->datum;
1668 k1 = h->key;
1669 if (key == k1)
1671 /* found one */
1672 break;
1674 li = LL_NEXT(ll, li);
1676 li = NULL;
1678 /* is there already one there? */
1679 if (li == NULL)
1681 /* add the unique element to the buckets list */
1682 ll_add(&(bucket->list), newli);
1683 return NULL;
1685 else
1687 /* free the stuff we just allocated */
1688 ll_freeitem(newli);
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
1702 void *
1703 hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1706 bucket_t *bucket;
1707 hash_item_lwpid *hi;
1708 llist *ll;
1709 llistitem *li;
1710 void *result = NULL;
1711 lwpid_t k1;
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);
1718 li = LL_FIRST(ll);
1719 while (li != NULL)
1721 hi = (hash_item_lwpid *)li->datum;
1722 k1 = hi->key;
1723 if (key == k1)
1725 /* found it: now replace the value with the new one */
1726 result = hi->value;
1727 hi->value = value;
1728 break;
1730 li = LL_NEXT(ll, li);
1733 /* if the element wasnt found, add it */
1734 if (result == NULL)
1736 li = ll_newitem(sizeof(hash_item_lwpid));
1737 hi = (hash_item_lwpid *)li->datum;
1738 hi->key = key;
1739 hi->value = value;
1740 ll_add(&(bucket->list), li);
1743 /* return the old value (so it can be freed) */
1744 return result;
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
1754 void *
1755 hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1758 bucket_t *bucket;
1759 llist *ll;
1760 llistitem *li;
1761 hash_item_lwpid *h;
1762 void *result;
1763 lwpid_t k1;
1765 result = NULL;
1766 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1768 ll = &(bucket->list);
1769 li = LL_FIRST(ll);
1770 while (li != NULL)
1772 h = (hash_item_lwpid *)li->datum;
1773 k1 = h->key;
1774 if (key == k1)
1776 result = h->value;
1777 break;
1779 li = LL_NEXT(ll, li);
1782 return result;
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.
1792 void *
1793 hash_remove_lwpid(hash_table *ht, lwpid_t key)
1796 bucket_t *bucket;
1797 llist *ll;
1798 llistitem *li;
1799 llistitem *lilast;
1800 hash_item_lwpid *hi;
1801 void *result;
1802 lwpid_t k1;
1804 result = NULL;
1805 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1807 ll = &(bucket->list);
1808 li = LL_FIRST(ll);
1809 lilast = NULL;
1810 while (li != NULL)
1812 hi = (hash_item_lwpid *)li->datum;
1813 k1 = hi->key;
1814 if (key == k1)
1816 ll_extract(ll, li, lilast);
1817 result = hi->value;
1818 key = hi->key;
1820 ll_freeitem(li);
1821 break;
1823 lilast = li;
1824 li = LL_NEXT(ll, li);
1827 return result;
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.
1838 hash_item_lwpid *
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;
1845 pos->curr = 0;
1846 pos->ll_last = NULL;
1848 /* find the first non-empty bucket */
1849 while(pos->hash_bucket->list.count == 0)
1851 pos->hash_bucket++;
1852 if (++pos->curr >= pos->num_buckets)
1854 return NULL;
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.
1872 hash_item_lwpid *
1873 hash_next_lwpid(hash_pos *pos)
1876 llistitem *li;
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 */
1885 return NULL;
1887 /* no: regrab first item in current bucket list (might be NULL) */
1888 li = LL_FIRST(&(pos->hash_bucket->list));
1890 else
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 */
1897 while (li == NULL)
1899 /* locate another bucket */
1900 pos->ll_last = NULL;
1902 /* move to the next one */
1903 pos->hash_bucket++;
1904 if (++pos->curr >= pos->num_buckets)
1906 /* at the end of the hash table */
1907 pos->ll_item = NULL;
1908 return 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 */
1916 pos->ll_item = li;
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.
1928 void *
1929 hash_remove_pos_lwpid(hash_pos *pos)
1932 llistitem *li;
1933 void *ans;
1934 hash_item_lwpid *hi;
1935 lwpid_t key;
1937 /* sanity checks */
1938 if (pos == NULL || pos->ll_last == pos->ll_item)
1940 return NULL;
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 */
1946 li = pos->ll_item;
1947 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1949 /* retain the data */
1950 hi = (hash_item_lwpid *)li->datum;
1951 ans = hi->value;
1953 /* free up the space */
1954 key = hi->key;
1956 ll_freeitem(li);
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;
1962 return ans;
1965 #endif