etc/protocols - sync with NetBSD-8
[minix.git] / external / bsd / top / dist / hash.c
blobc1a2d6ee2c3e601b5ebc60a71e3a77fa069cc7ec
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;
583 /* sanity checks */
584 if (pos == NULL || pos->ll_last == pos->ll_item)
586 return NULL;
589 /* at this point pos contains the item to remove (ll_item)
590 and its predecesor (ll_last) */
591 /* extract the item from the llist */
592 li = pos->ll_item;
593 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
595 /* retain the data */
596 hi = (hash_item_uint *)li->datum;
597 ans = hi->value;
599 ll_freeitem(li);
601 /* back up to previous item */
602 /* its okay for ll_item to be null: hash_next will detect it */
603 pos->ll_item = pos->ll_last;
605 return ans;
611 * void hash_add_pid(hash_table *ht, pid_t key, void *value)
613 * Add an element to table "ht". The element is described by
614 * "key" and "value". Return NULL on success. If the key
615 * already exists in the table, then no action is taken and
616 * the data for the existing element is returned.
617 * Key type is pid_t
620 void *
621 hash_add_pid(hash_table *ht, pid_t key, void *value)
624 bucket_t *bucket;
625 hash_item_pid *hi;
626 hash_item_pid *h;
627 llist *ll;
628 llistitem *li;
629 llistitem *newli;
630 pid_t k1;
632 /* allocate the space we will need */
633 newli = ll_newitem(sizeof(hash_item_pid));
634 hi = (hash_item_pid *)newli->datum;
636 /* fill in the values */
637 hi->key = key;
638 hi->value = value;
640 /* hash to the bucket */
641 bucket = &(ht->buckets[(key % ht->num_buckets)]);
643 /* walk the list to make sure we do not have a duplicate */
644 ll = &(bucket->list);
645 li = LL_FIRST(ll);
646 while (li != NULL)
648 h = (hash_item_pid *)li->datum;
649 k1 = h->key;
650 if (key == k1)
652 /* found one */
653 break;
655 li = LL_NEXT(ll, li);
657 li = NULL;
659 /* is there already one there? */
660 if (li == NULL)
662 /* add the unique element to the buckets list */
663 ll_add(&(bucket->list), newli);
664 return NULL;
666 else
668 /* free the stuff we just allocated */
669 ll_freeitem(newli);
670 return ((hash_item_pid *)(li->datum))->value;
675 * void *hash_replace_pid(hash_table *ht, pid_t key, void *value)
677 * Replace an existing value in the hash table with a new one and
678 * return the old value. If the key does not already exist in
679 * the hash table, add a new element and return NULL.
680 * Key type is pid_t
683 void *
684 hash_replace_pid(hash_table *ht, pid_t key, void *value)
687 bucket_t *bucket;
688 hash_item_pid *hi;
689 llist *ll;
690 llistitem *li;
691 void *result = NULL;
692 pid_t k1;
694 /* find the bucket */
695 bucket = &(ht->buckets[(key % ht->num_buckets)]);
697 /* walk the list until we find the existing item */
698 ll = &(bucket->list);
699 li = LL_FIRST(ll);
700 while (li != NULL)
702 hi = (hash_item_pid *)li->datum;
703 k1 = hi->key;
704 if (key == k1)
706 /* found it: now replace the value with the new one */
707 result = hi->value;
708 hi->value = value;
709 break;
711 li = LL_NEXT(ll, li);
714 /* if the element wasnt found, add it */
715 if (result == NULL)
717 li = ll_newitem(sizeof(hash_item_pid));
718 hi = (hash_item_pid *)li->datum;
719 hi->key = key;
720 hi->value = value;
721 ll_add(&(bucket->list), li);
724 /* return the old value (so it can be freed) */
725 return result;
729 * void *hash_lookup_pid(hash_table *ht, pid_t key)
731 * Look up "key" in "ht" and return the associated value. If "key"
732 * is not found, return NULL. Key type is pid_t
735 void *
736 hash_lookup_pid(hash_table *ht, pid_t key)
739 bucket_t *bucket;
740 llist *ll;
741 llistitem *li;
742 hash_item_pid *h;
743 void *result;
744 pid_t k1;
746 result = NULL;
747 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
749 ll = &(bucket->list);
750 li = LL_FIRST(ll);
751 while (li != NULL)
753 h = (hash_item_pid *)li->datum;
754 k1 = h->key;
755 if (key == k1)
757 result = h->value;
758 break;
760 li = LL_NEXT(ll, li);
763 return result;
767 * void *hash_remove_pid(hash_table *ht, pid_t key)
769 * Remove the element associated with "key" from the hash table
770 * "ht". Return the value or NULL if the key was not found.
773 void *
774 hash_remove_pid(hash_table *ht, pid_t key)
777 bucket_t *bucket;
778 llist *ll;
779 llistitem *li;
780 llistitem *lilast;
781 hash_item_pid *hi;
782 void *result;
783 pid_t k1;
785 result = NULL;
786 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
788 ll = &(bucket->list);
789 li = LL_FIRST(ll);
790 lilast = NULL;
791 while (li != NULL)
793 hi = (hash_item_pid *)li->datum;
794 k1 = hi->key;
795 if (key == k1)
797 ll_extract(ll, li, lilast);
798 result = hi->value;
799 key = hi->key;
801 ll_freeitem(li);
802 break;
804 lilast = li;
805 li = LL_NEXT(ll, li);
808 return result;
812 * hash_item_pid *hash_first_pid(hash_table *ht, hash_pos *pos)
814 * First function to call when iterating through all items in the hash
815 * table. Returns the first item in "ht" and initializes "*pos" to track
816 * the current position.
819 hash_item_pid *
820 hash_first_pid(hash_table *ht, hash_pos *pos)
823 /* initialize pos for first item in first bucket */
824 pos->num_buckets = ht->num_buckets;
825 pos->hash_bucket = ht->buckets;
826 pos->curr = 0;
827 pos->ll_last = NULL;
829 /* find the first non-empty bucket */
830 while(pos->hash_bucket->list.count == 0)
832 pos->hash_bucket++;
833 if (++pos->curr >= pos->num_buckets)
835 return NULL;
839 /* set and return the first item */
840 pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
841 return (hash_item_pid *)pos->ll_item->datum;
846 * hash_item_pid *hash_next_pid(hash_pos *pos)
848 * Return the next item in the hash table, using "pos" as a description
849 * of the present position in the hash table. "pos" also identifies the
850 * specific hash table. Return NULL if there are no more elements.
853 hash_item_pid *
854 hash_next_pid(hash_pos *pos)
857 llistitem *li;
859 /* move item to last and check for NULL */
860 if ((pos->ll_last = pos->ll_item) == NULL)
862 /* are we really at the end of the hash table? */
863 if (pos->curr >= pos->num_buckets)
865 /* yes: return NULL */
866 return NULL;
868 /* no: regrab first item in current bucket list (might be NULL) */
869 li = LL_FIRST(&(pos->hash_bucket->list));
871 else
873 /* get the next item in the llist */
874 li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
877 /* if its NULL we have to find another bucket */
878 while (li == NULL)
880 /* locate another bucket */
881 pos->ll_last = NULL;
883 /* move to the next one */
884 pos->hash_bucket++;
885 if (++pos->curr >= pos->num_buckets)
887 /* at the end of the hash table */
888 pos->ll_item = NULL;
889 return NULL;
892 /* get the first element (might be NULL) */
893 li = LL_FIRST(&(pos->hash_bucket->list));
896 /* li is the next element to dish out */
897 pos->ll_item = li;
898 return (hash_item_pid *)li->datum;
902 * void *hash_remove_pos_pid(hash_pos *pos)
904 * Remove the hash table entry pointed to by position marker "pos".
905 * The data from the entry is returned upon success, otherwise NULL.
909 void *
910 hash_remove_pos_pid(hash_pos *pos)
913 llistitem *li;
914 void *ans;
915 hash_item_pid *hi;
917 /* sanity checks */
918 if (pos == NULL || pos->ll_last == pos->ll_item)
920 return NULL;
923 /* at this point pos contains the item to remove (ll_item)
924 and its predecesor (ll_last) */
925 /* extract the item from the llist */
926 li = pos->ll_item;
927 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
929 /* retain the data */
930 hi = (hash_item_pid *)li->datum;
931 ans = hi->value;
933 /* free up the space */
934 ll_freeitem(li);
936 /* back up to previous item */
937 /* its okay for ll_item to be null: hash_next will detect it */
938 pos->ll_item = pos->ll_last;
940 return ans;
946 * void hash_add_string(hash_table *ht, char * key, void *value)
948 * Add an element to table "ht". The element is described by
949 * "key" and "value". Return NULL on success. If the key
950 * already exists in the table, then no action is taken and
951 * the data for the existing element is returned.
952 * Key type is char *
955 void *
956 hash_add_string(hash_table *ht, char * key, void *value)
959 bucket_t *bucket;
960 hash_item_string *hi;
961 hash_item_string *h;
962 llist *ll;
963 llistitem *li;
964 llistitem *newli;
965 char * k1;
967 /* allocate the space we will need */
968 newli = ll_newitem(sizeof(hash_item_string));
969 hi = (hash_item_string *)newli->datum;
971 /* fill in the values */
972 hi->key = estrdup(key);
973 hi->value = value;
975 /* hash to the bucket */
976 bucket = &(ht->buckets[string_hash(ht, key)]);
978 /* walk the list to make sure we do not have a duplicate */
979 ll = &(bucket->list);
980 li = LL_FIRST(ll);
981 while (li != NULL)
983 h = (hash_item_string *)li->datum;
984 k1 = h->key;
985 if (strcmp(key, k1) == 0)
987 /* found one */
988 break;
990 li = LL_NEXT(ll, li);
992 li = NULL;
994 /* is there already one there? */
995 if (li == NULL)
997 /* add the unique element to the buckets list */
998 ll_add(&(bucket->list), newli);
999 return NULL;
1001 else
1003 /* free the stuff we just allocated */
1004 ll_freeitem(newli);
1005 return ((hash_item_string *)(li->datum))->value;
1010 * void *hash_replace_string(hash_table *ht, char * key, void *value)
1012 * Replace an existing value in the hash table with a new one and
1013 * return the old value. If the key does not already exist in
1014 * the hash table, add a new element and return NULL.
1015 * Key type is char *
1018 void *
1019 hash_replace_string(hash_table *ht, char * key, void *value)
1022 bucket_t *bucket;
1023 hash_item_string *hi;
1024 llist *ll;
1025 llistitem *li;
1026 void *result = NULL;
1027 char * k1;
1029 /* find the bucket */
1030 bucket = &(ht->buckets[string_hash(ht, key)]);
1032 /* walk the list until we find the existing item */
1033 ll = &(bucket->list);
1034 li = LL_FIRST(ll);
1035 while (li != NULL)
1037 hi = (hash_item_string *)li->datum;
1038 k1 = hi->key;
1039 if (strcmp(key, k1) == 0)
1041 /* found it: now replace the value with the new one */
1042 result = hi->value;
1043 hi->value = value;
1044 break;
1046 li = LL_NEXT(ll, li);
1049 /* if the element wasnt found, add it */
1050 if (result == NULL)
1052 li = ll_newitem(sizeof(hash_item_string));
1053 hi = (hash_item_string *)li->datum;
1054 hi->key = estrdup(key);
1055 hi->value = value;
1056 ll_add(&(bucket->list), li);
1059 /* return the old value (so it can be freed) */
1060 return result;
1064 * void *hash_lookup_string(hash_table *ht, char * key)
1066 * Look up "key" in "ht" and return the associated value. If "key"
1067 * is not found, return NULL. Key type is char *
1070 void *
1071 hash_lookup_string(hash_table *ht, char * key)
1074 bucket_t *bucket;
1075 llist *ll;
1076 llistitem *li;
1077 hash_item_string *h;
1078 void *result;
1079 char * k1;
1081 result = NULL;
1082 if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1084 ll = &(bucket->list);
1085 li = LL_FIRST(ll);
1086 while (li != NULL)
1088 h = (hash_item_string *)li->datum;
1089 k1 = h->key;
1090 if (strcmp(key, k1) == 0)
1092 result = h->value;
1093 break;
1095 li = LL_NEXT(ll, li);
1098 return result;
1102 * void *hash_remove_string(hash_table *ht, char * key)
1104 * Remove the element associated with "key" from the hash table
1105 * "ht". Return the value or NULL if the key was not found.
1108 void *
1109 hash_remove_string(hash_table *ht, char * key)
1112 bucket_t *bucket;
1113 llist *ll;
1114 llistitem *li;
1115 llistitem *lilast;
1116 hash_item_string *hi;
1117 void *result;
1118 char * k1;
1120 result = NULL;
1121 if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1123 ll = &(bucket->list);
1124 li = LL_FIRST(ll);
1125 lilast = NULL;
1126 while (li != NULL)
1128 hi = (hash_item_string *)li->datum;
1129 k1 = hi->key;
1130 if (strcmp(key, k1) == 0)
1132 ll_extract(ll, li, lilast);
1133 result = hi->value;
1134 key = hi->key;
1135 free(key);
1136 ll_freeitem(li);
1137 break;
1139 lilast = li;
1140 li = LL_NEXT(ll, li);
1143 return result;
1147 * hash_item_string *hash_first_string(hash_table *ht, hash_pos *pos)
1149 * First function to call when iterating through all items in the hash
1150 * table. Returns the first item in "ht" and initializes "*pos" to track
1151 * the current position.
1154 hash_item_string *
1155 hash_first_string(hash_table *ht, hash_pos *pos)
1158 /* initialize pos for first item in first bucket */
1159 pos->num_buckets = ht->num_buckets;
1160 pos->hash_bucket = ht->buckets;
1161 pos->curr = 0;
1162 pos->ll_last = NULL;
1164 /* find the first non-empty bucket */
1165 while(pos->hash_bucket->list.count == 0)
1167 pos->hash_bucket++;
1168 if (++pos->curr >= pos->num_buckets)
1170 return NULL;
1174 /* set and return the first item */
1175 pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
1176 return (hash_item_string *)pos->ll_item->datum;
1181 * hash_item_string *hash_next_string(hash_pos *pos)
1183 * Return the next item in the hash table, using "pos" as a description
1184 * of the present position in the hash table. "pos" also identifies the
1185 * specific hash table. Return NULL if there are no more elements.
1188 hash_item_string *
1189 hash_next_string(hash_pos *pos)
1192 llistitem *li;
1194 /* move item to last and check for NULL */
1195 if ((pos->ll_last = pos->ll_item) == NULL)
1197 /* are we really at the end of the hash table? */
1198 if (pos->curr >= pos->num_buckets)
1200 /* yes: return NULL */
1201 return NULL;
1203 /* no: regrab first item in current bucket list (might be NULL) */
1204 li = LL_FIRST(&(pos->hash_bucket->list));
1206 else
1208 /* get the next item in the llist */
1209 li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1212 /* if its NULL we have to find another bucket */
1213 while (li == NULL)
1215 /* locate another bucket */
1216 pos->ll_last = NULL;
1218 /* move to the next one */
1219 pos->hash_bucket++;
1220 if (++pos->curr >= pos->num_buckets)
1222 /* at the end of the hash table */
1223 pos->ll_item = NULL;
1224 return NULL;
1227 /* get the first element (might be NULL) */
1228 li = LL_FIRST(&(pos->hash_bucket->list));
1231 /* li is the next element to dish out */
1232 pos->ll_item = li;
1233 return (hash_item_string *)li->datum;
1237 * void *hash_remove_pos_string(hash_pos *pos)
1239 * Remove the hash table entry pointed to by position marker "pos".
1240 * The data from the entry is returned upon success, otherwise NULL.
1244 void *
1245 hash_remove_pos_string(hash_pos *pos)
1248 llistitem *li;
1249 void *ans;
1250 hash_item_string *hi;
1251 char * key;
1253 /* sanity checks */
1254 if (pos == NULL || pos->ll_last == pos->ll_item)
1256 return NULL;
1259 /* at this point pos contains the item to remove (ll_item)
1260 and its predecesor (ll_last) */
1261 /* extract the item from the llist */
1262 li = pos->ll_item;
1263 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1265 /* retain the data */
1266 hi = (hash_item_string *)li->datum;
1267 ans = hi->value;
1269 /* free up the space */
1270 key = hi->key;
1271 free(key);
1272 ll_freeitem(li);
1274 /* back up to previous item */
1275 /* its okay for ll_item to be null: hash_next will detect it */
1276 pos->ll_item = pos->ll_last;
1278 return ans;
1284 * void hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1286 * Add an element to table "ht". The element is described by
1287 * "key" and "value". Return NULL on success. If the key
1288 * already exists in the table, then no action is taken and
1289 * the data for the existing element is returned.
1290 * Key type is pidthr_t
1293 void *
1294 hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1297 bucket_t *bucket;
1298 hash_item_pidthr *hi;
1299 hash_item_pidthr *h;
1300 llist *ll;
1301 llistitem *li;
1302 llistitem *newli;
1303 pidthr_t k1;
1305 /* allocate the space we will need */
1306 newli = ll_newitem(sizeof(hash_item_pidthr));
1307 hi = (hash_item_pidthr *)newli->datum;
1309 /* fill in the values */
1310 hi->key = key;
1311 hi->value = value;
1313 /* hash to the bucket */
1314 bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
1316 /* walk the list to make sure we do not have a duplicate */
1317 ll = &(bucket->list);
1318 li = LL_FIRST(ll);
1319 while (li != NULL)
1321 h = (hash_item_pidthr *)li->datum;
1322 k1 = h->key;
1323 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1325 /* found one */
1326 break;
1328 li = LL_NEXT(ll, li);
1330 li = NULL;
1332 /* is there already one there? */
1333 if (li == NULL)
1335 /* add the unique element to the buckets list */
1336 ll_add(&(bucket->list), newli);
1337 return NULL;
1339 else
1341 /* free the stuff we just allocated */
1342 ll_freeitem(newli);
1343 return ((hash_item_pidthr *)(li->datum))->value;
1348 * void *hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1350 * Replace an existing value in the hash table with a new one and
1351 * return the old value. If the key does not already exist in
1352 * the hash table, add a new element and return NULL.
1353 * Key type is pidthr_t
1356 void *
1357 hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1360 bucket_t *bucket;
1361 hash_item_pidthr *hi;
1362 llist *ll;
1363 llistitem *li;
1364 void *result = NULL;
1365 pidthr_t k1;
1367 /* find the bucket */
1368 bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
1370 /* walk the list until we find the existing item */
1371 ll = &(bucket->list);
1372 li = LL_FIRST(ll);
1373 while (li != NULL)
1375 hi = (hash_item_pidthr *)li->datum;
1376 k1 = hi->key;
1377 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1379 /* found it: now replace the value with the new one */
1380 result = hi->value;
1381 hi->value = value;
1382 break;
1384 li = LL_NEXT(ll, li);
1387 /* if the element wasnt found, add it */
1388 if (result == NULL)
1390 li = ll_newitem(sizeof(hash_item_pidthr));
1391 hi = (hash_item_pidthr *)li->datum;
1392 hi->key = key;
1393 hi->value = value;
1394 ll_add(&(bucket->list), li);
1397 /* return the old value (so it can be freed) */
1398 return result;
1402 * void *hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1404 * Look up "key" in "ht" and return the associated value. If "key"
1405 * is not found, return NULL. Key type is pidthr_t
1408 void *
1409 hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1412 bucket_t *bucket;
1413 llist *ll;
1414 llistitem *li;
1415 hash_item_pidthr *h;
1416 void *result;
1417 pidthr_t k1;
1419 result = NULL;
1420 if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1422 ll = &(bucket->list);
1423 li = LL_FIRST(ll);
1424 while (li != NULL)
1426 h = (hash_item_pidthr *)li->datum;
1427 k1 = h->key;
1428 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1430 result = h->value;
1431 break;
1433 li = LL_NEXT(ll, li);
1436 return result;
1440 * void *hash_remove_pidthr(hash_table *ht, pidthr_t key)
1442 * Remove the element associated with "key" from the hash table
1443 * "ht". Return the value or NULL if the key was not found.
1446 void *
1447 hash_remove_pidthr(hash_table *ht, pidthr_t key)
1450 bucket_t *bucket;
1451 llist *ll;
1452 llistitem *li;
1453 llistitem *lilast;
1454 hash_item_pidthr *hi;
1455 void *result;
1456 pidthr_t k1;
1458 result = NULL;
1459 if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1461 ll = &(bucket->list);
1462 li = LL_FIRST(ll);
1463 lilast = NULL;
1464 while (li != NULL)
1466 hi = (hash_item_pidthr *)li->datum;
1467 k1 = hi->key;
1468 if ((key.k_pid == k1.k_pid && key.k_thr == k1.k_thr))
1470 ll_extract(ll, li, lilast);
1471 result = hi->value;
1472 key = hi->key;
1474 ll_freeitem(li);
1475 break;
1477 lilast = li;
1478 li = LL_NEXT(ll, li);
1481 return result;
1485 * hash_item_pidthr *hash_first_pidthr(hash_table *ht, hash_pos *pos)
1487 * First function to call when iterating through all items in the hash
1488 * table. Returns the first item in "ht" and initializes "*pos" to track
1489 * the current position.
1492 hash_item_pidthr *
1493 hash_first_pidthr(hash_table *ht, hash_pos *pos)
1496 /* initialize pos for first item in first bucket */
1497 pos->num_buckets = ht->num_buckets;
1498 pos->hash_bucket = ht->buckets;
1499 pos->curr = 0;
1500 pos->ll_last = NULL;
1502 /* find the first non-empty bucket */
1503 while(pos->hash_bucket->list.count == 0)
1505 pos->hash_bucket++;
1506 if (++pos->curr >= pos->num_buckets)
1508 return NULL;
1512 /* set and return the first item */
1513 pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
1514 return (hash_item_pidthr *)pos->ll_item->datum;
1519 * hash_item_pidthr *hash_next_pidthr(hash_pos *pos)
1521 * Return the next item in the hash table, using "pos" as a description
1522 * of the present position in the hash table. "pos" also identifies the
1523 * specific hash table. Return NULL if there are no more elements.
1526 hash_item_pidthr *
1527 hash_next_pidthr(hash_pos *pos)
1530 llistitem *li;
1532 /* move item to last and check for NULL */
1533 if ((pos->ll_last = pos->ll_item) == NULL)
1535 /* are we really at the end of the hash table? */
1536 if (pos->curr >= pos->num_buckets)
1538 /* yes: return NULL */
1539 return NULL;
1541 /* no: regrab first item in current bucket list (might be NULL) */
1542 li = LL_FIRST(&(pos->hash_bucket->list));
1544 else
1546 /* get the next item in the llist */
1547 li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1550 /* if its NULL we have to find another bucket */
1551 while (li == NULL)
1553 /* locate another bucket */
1554 pos->ll_last = NULL;
1556 /* move to the next one */
1557 pos->hash_bucket++;
1558 if (++pos->curr >= pos->num_buckets)
1560 /* at the end of the hash table */
1561 pos->ll_item = NULL;
1562 return NULL;
1565 /* get the first element (might be NULL) */
1566 li = LL_FIRST(&(pos->hash_bucket->list));
1569 /* li is the next element to dish out */
1570 pos->ll_item = li;
1571 return (hash_item_pidthr *)li->datum;
1575 * void *hash_remove_pos_pidthr(hash_pos *pos)
1577 * Remove the hash table entry pointed to by position marker "pos".
1578 * The data from the entry is returned upon success, otherwise NULL.
1582 void *
1583 hash_remove_pos_pidthr(hash_pos *pos)
1586 llistitem *li;
1587 void *ans;
1588 hash_item_pidthr *hi;
1590 /* sanity checks */
1591 if (pos == NULL || pos->ll_last == pos->ll_item)
1593 return NULL;
1596 /* at this point pos contains the item to remove (ll_item)
1597 and its predecesor (ll_last) */
1598 /* extract the item from the llist */
1599 li = pos->ll_item;
1600 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1602 /* retain the data */
1603 hi = (hash_item_pidthr *)li->datum;
1604 ans = hi->value;
1606 /* free up the space */
1607 ll_freeitem(li);
1609 /* back up to previous item */
1610 /* its okay for ll_item to be null: hash_next will detect it */
1611 pos->ll_item = pos->ll_last;
1613 return ans;
1616 #if HAVE_LWPID_T
1620 * void hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1622 * Add an element to table "ht". The element is described by
1623 * "key" and "value". Return NULL on success. If the key
1624 * already exists in the table, then no action is taken and
1625 * the data for the existing element is returned.
1626 * Key type is lwpid_t
1629 void *
1630 hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1633 bucket_t *bucket;
1634 hash_item_lwpid *hi;
1635 hash_item_lwpid *h;
1636 llist *ll;
1637 llistitem *li;
1638 llistitem *newli;
1639 lwpid_t k1;
1641 /* allocate the space we will need */
1642 newli = ll_newitem(sizeof(hash_item_lwpid));
1643 hi = (hash_item_lwpid *)newli->datum;
1645 /* fill in the values */
1646 hi->key = key;
1647 hi->value = value;
1649 /* hash to the bucket */
1650 bucket = &(ht->buckets[(key % ht->num_buckets)]);
1652 /* walk the list to make sure we do not have a duplicate */
1653 ll = &(bucket->list);
1654 li = LL_FIRST(ll);
1655 while (li != NULL)
1657 h = (hash_item_lwpid *)li->datum;
1658 k1 = h->key;
1659 if (key == k1)
1661 /* found one */
1662 break;
1664 li = LL_NEXT(ll, li);
1666 li = NULL;
1668 /* is there already one there? */
1669 if (li == NULL)
1671 /* add the unique element to the buckets list */
1672 ll_add(&(bucket->list), newli);
1673 return NULL;
1675 else
1677 /* free the stuff we just allocated */
1678 ll_freeitem(newli);
1679 return ((hash_item_lwpid *)(li->datum))->value;
1684 * void *hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1686 * Replace an existing value in the hash table with a new one and
1687 * return the old value. If the key does not already exist in
1688 * the hash table, add a new element and return NULL.
1689 * Key type is lwpid_t
1692 void *
1693 hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1696 bucket_t *bucket;
1697 hash_item_lwpid *hi;
1698 llist *ll;
1699 llistitem *li;
1700 void *result = NULL;
1701 lwpid_t k1;
1703 /* find the bucket */
1704 bucket = &(ht->buckets[(key % ht->num_buckets)]);
1706 /* walk the list until we find the existing item */
1707 ll = &(bucket->list);
1708 li = LL_FIRST(ll);
1709 while (li != NULL)
1711 hi = (hash_item_lwpid *)li->datum;
1712 k1 = hi->key;
1713 if (key == k1)
1715 /* found it: now replace the value with the new one */
1716 result = hi->value;
1717 hi->value = value;
1718 break;
1720 li = LL_NEXT(ll, li);
1723 /* if the element wasnt found, add it */
1724 if (result == NULL)
1726 li = ll_newitem(sizeof(hash_item_lwpid));
1727 hi = (hash_item_lwpid *)li->datum;
1728 hi->key = key;
1729 hi->value = value;
1730 ll_add(&(bucket->list), li);
1733 /* return the old value (so it can be freed) */
1734 return result;
1738 * void *hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1740 * Look up "key" in "ht" and return the associated value. If "key"
1741 * is not found, return NULL. Key type is lwpid_t
1744 void *
1745 hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1748 bucket_t *bucket;
1749 llist *ll;
1750 llistitem *li;
1751 hash_item_lwpid *h;
1752 void *result;
1753 lwpid_t k1;
1755 result = NULL;
1756 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1758 ll = &(bucket->list);
1759 li = LL_FIRST(ll);
1760 while (li != NULL)
1762 h = (hash_item_lwpid *)li->datum;
1763 k1 = h->key;
1764 if (key == k1)
1766 result = h->value;
1767 break;
1769 li = LL_NEXT(ll, li);
1772 return result;
1776 * void *hash_remove_lwpid(hash_table *ht, lwpid_t key)
1778 * Remove the element associated with "key" from the hash table
1779 * "ht". Return the value or NULL if the key was not found.
1782 void *
1783 hash_remove_lwpid(hash_table *ht, lwpid_t key)
1786 bucket_t *bucket;
1787 llist *ll;
1788 llistitem *li;
1789 llistitem *lilast;
1790 hash_item_lwpid *hi;
1791 void *result;
1792 lwpid_t k1;
1794 result = NULL;
1795 if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1797 ll = &(bucket->list);
1798 li = LL_FIRST(ll);
1799 lilast = NULL;
1800 while (li != NULL)
1802 hi = (hash_item_lwpid *)li->datum;
1803 k1 = hi->key;
1804 if (key == k1)
1806 ll_extract(ll, li, lilast);
1807 result = hi->value;
1808 key = hi->key;
1810 ll_freeitem(li);
1811 break;
1813 lilast = li;
1814 li = LL_NEXT(ll, li);
1817 return result;
1821 * hash_item_lwpid *hash_first_lwpid(hash_table *ht, hash_pos *pos)
1823 * First function to call when iterating through all items in the hash
1824 * table. Returns the first item in "ht" and initializes "*pos" to track
1825 * the current position.
1828 hash_item_lwpid *
1829 hash_first_lwpid(hash_table *ht, hash_pos *pos)
1832 /* initialize pos for first item in first bucket */
1833 pos->num_buckets = ht->num_buckets;
1834 pos->hash_bucket = ht->buckets;
1835 pos->curr = 0;
1836 pos->ll_last = NULL;
1838 /* find the first non-empty bucket */
1839 while(pos->hash_bucket->list.count == 0)
1841 pos->hash_bucket++;
1842 if (++pos->curr >= pos->num_buckets)
1844 return NULL;
1848 /* set and return the first item */
1849 pos->ll_item = LL_FIRST(&(pos->hash_bucket->list));
1850 return (hash_item_lwpid *)pos->ll_item->datum;
1855 * hash_item_lwpid *hash_next_lwpid(hash_pos *pos)
1857 * Return the next item in the hash table, using "pos" as a description
1858 * of the present position in the hash table. "pos" also identifies the
1859 * specific hash table. Return NULL if there are no more elements.
1862 hash_item_lwpid *
1863 hash_next_lwpid(hash_pos *pos)
1866 llistitem *li;
1868 /* move item to last and check for NULL */
1869 if ((pos->ll_last = pos->ll_item) == NULL)
1871 /* are we really at the end of the hash table? */
1872 if (pos->curr >= pos->num_buckets)
1874 /* yes: return NULL */
1875 return NULL;
1877 /* no: regrab first item in current bucket list (might be NULL) */
1878 li = LL_FIRST(&(pos->hash_bucket->list));
1880 else
1882 /* get the next item in the llist */
1883 li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1886 /* if its NULL we have to find another bucket */
1887 while (li == NULL)
1889 /* locate another bucket */
1890 pos->ll_last = NULL;
1892 /* move to the next one */
1893 pos->hash_bucket++;
1894 if (++pos->curr >= pos->num_buckets)
1896 /* at the end of the hash table */
1897 pos->ll_item = NULL;
1898 return NULL;
1901 /* get the first element (might be NULL) */
1902 li = LL_FIRST(&(pos->hash_bucket->list));
1905 /* li is the next element to dish out */
1906 pos->ll_item = li;
1907 return (hash_item_lwpid *)li->datum;
1911 * void *hash_remove_pos_lwpid(hash_pos *pos)
1913 * Remove the hash table entry pointed to by position marker "pos".
1914 * The data from the entry is returned upon success, otherwise NULL.
1918 void *
1919 hash_remove_pos_lwpid(hash_pos *pos)
1922 llistitem *li;
1923 void *ans;
1924 hash_item_lwpid *hi;
1926 /* sanity checks */
1927 if (pos == NULL || pos->ll_last == pos->ll_item)
1929 return NULL;
1932 /* at this point pos contains the item to remove (ll_item)
1933 and its predecesor (ll_last) */
1934 /* extract the item from the llist */
1935 li = pos->ll_item;
1936 ll_extract(&(pos->hash_bucket->list), li, pos->ll_last);
1938 /* retain the data */
1939 hi = (hash_item_lwpid *)li->datum;
1940 ans = hi->value;
1942 /* free up the space */
1943 ll_freeitem(li);
1945 /* back up to previous item */
1946 /* its okay for ll_item to be null: hash_next will detect it */
1947 pos->ll_item = pos->ll_last;
1949 return ans;
1952 #endif