xref: /minix/external/bsd/top/dist/hash.c (revision b89261ba)
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.
10  *
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.
15  *
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.
19  *
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.
31  */
32 
33 /* hash.m4c */
34 
35 /* The file hash.c is generated from hash.m4c via the preprocessor M4 */
36 
37 /*
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.
43  */
44 
45 #include "os.h"
46 
47 #ifdef HAVE_MATH_H
48 #include <math.h>
49 #endif
50 
51 #include "hash.h"
52 
53 static int
next_prime(int x)54 next_prime(int x)
55 
56 {
57     double i, j;
58     int f;
59 
60     i = x;
61     while (i++)
62     {
63 	f=1;
64 	for (j=2; j<i; j++)
65 	{
66 	    if ((i/j)==floor(i/j))
67 	    {
68 		f=0;
69 		break;
70 	    }
71 	}
72 	if (f)
73 	{
74 	    return (int)i;
75 	}
76     }
77     return 1;
78 }
79 
80 /* string hashes */
81 
82 static int
string_hash(hash_table * ht,char * key)83 string_hash(hash_table *ht, char *key)
84 
85 {
86     unsigned long s = 0;
87     unsigned char ch;
88     int shifting = 24;
89 
90     while ((ch = (unsigned char)*key++) != '\0')
91     {
92 	if (shifting == 0)
93 	{
94 	    s = s + ch;
95 	    shifting = 24;
96 	}
97 	else
98 	{
99 	    s = s + (ch << shifting);
100 	    shifting -= 8;
101 	}
102     }
103 
104     return (s % ht->num_buckets);
105 }
106 
ll_init(llist * q)107 static void ll_init(llist *q)
108 
109 {
110     q->head = NULL;
111     q->count = 0;
112 }
113 
ll_newitem(int size)114 static llistitem *ll_newitem(int size)
115 
116 {
117     llistitem *qi;
118 
119     qi = emalloc(sizeof(llistitem) + size);
120     qi->datum = ((char *)qi + sizeof(llistitem));
121     return qi;
122 }
123 
ll_freeitem(llistitem * li)124 static void ll_freeitem(llistitem *li)
125 
126 {
127     free(li);
128 }
129 
ll_add(llist * q,llistitem * new)130 static void ll_add(llist *q, llistitem *new)
131 
132 {
133     new->next = q->head;
134     q->head = new;
135     q->count++;
136 }
137 
ll_extract(llist * q,llistitem * qi,llistitem * last)138 static void ll_extract(llist *q, llistitem *qi, llistitem *last)
139 
140 {
141     if (last == NULL)
142     {
143 	q->head = qi->next;
144     }
145     else
146     {
147 	last->next = qi->next;
148     }
149     qi->next = NULL;
150     q->count--;
151 }
152 
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)
156 
157 #ifdef notdef
158 static llistitem *
ll_first(llist * q)159 ll_first(llist *q)
160 
161 {
162     return q->head;
163 }
164 
165 static llistitem *
ll_next(llist * q,llistitem * qi)166 ll_next(llist *q, llistitem *qi)
167 
168 {
169     return (qi != NULL ? qi->next : NULL);
170 }
171 
172 static int
ll_isempty(llist * ll)173 ll_isempty(llist *ll)
174 
175 {
176     return (ll->count == 0);
177 }
178 #endif
179 
180 /*
181  * hash_table *hash_create(int num)
182  *
183  * Creates a hash table structure with at least "num" buckets.
184  */
185 
186 hash_table *
hash_create(int num)187 hash_create(int num)
188 
189 {
190     hash_table *result;
191     bucket_t *b;
192     int bytes;
193     int i;
194 
195     /* create the resultant structure */
196     result = emalloc(sizeof(hash_table));
197 
198     /* adjust bucket count to be prime */
199     num = next_prime(num);
200 
201     /* create the buckets */
202     bytes = sizeof(bucket_t) * num;
203     result->buckets = b = emalloc(bytes);
204     result->num_buckets = num;
205 
206     /* create each bucket as a linked list */
207     i = num;
208     while (--i >= 0)
209     {
210 	ll_init(&(b->list));
211 	b++;
212     }
213 
214     return result;
215 }
216 
217 /*
218  * unsigned int hash_count(hash_table *ht)
219  *
220  * Return total number of elements contained in hash table.
221  */
222 
223 #ifdef notdef
224 static unsigned int
hash_count(hash_table * ht)225 hash_count(hash_table *ht)
226 
227 {
228     register int i = 0;
229     register int cnt = 0;
230     register bucket_t *bucket;
231 
232     bucket = ht->buckets;
233     while (i++ < ht->num_buckets)
234     {
235 	cnt += bucket->list.count;
236 	bucket++;
237     }
238 
239     return cnt;
240 }
241 #endif
242 
243 /*
244  * void hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
245  *
246  * Fill in "sizes" with information about bucket lengths in hash
247  * table "max".
248  */
249 
250 void
hash_sizeinfo(unsigned int * sizes,int max,hash_table * ht)251 hash_sizeinfo(unsigned int *sizes, int max, hash_table *ht)
252 
253 {
254     register int i;
255     register int idx;
256     register bucket_t *bucket;
257 
258     memzero(sizes, max * sizeof(unsigned int));
259 
260     bucket = ht->buckets;
261     i = 0;
262     while (i++ < ht->num_buckets)
263     {
264 	idx = bucket->list.count;
265 	sizes[idx >= max ? max-1 : idx]++;
266 	bucket++;
267     }
268 }
269 
270 
271 
272 
273 
274 
275 
276 /*
277  * void hash_add_uint(hash_table *ht, unsigned int key, void *value)
278  *
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
284  */
285 
286 void *
hash_add_uint(hash_table * ht,unsigned int key,void * value)287 hash_add_uint(hash_table *ht, unsigned int key, void *value)
288 
289 {
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;
297 
298     /* allocate the space we will need */
299     newli = ll_newitem(sizeof(hash_item_uint));
300     hi = (hash_item_uint *)newli->datum;
301 
302     /* fill in the values */
303     hi->key = key;
304     hi->value = value;
305 
306     /* hash to the bucket */
307     bucket = &(ht->buckets[(key % ht->num_buckets)]);
308 
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)
313     {
314 	h = (hash_item_uint *)li->datum;
315 	k1 = h->key;
316 	if (key == k1)
317 	{
318 	    /* found one */
319 	    break;
320 	}
321 	li = LL_NEXT(ll, li);
322     }
323     li = NULL;
324 
325     /* is there already one there? */
326     if (li == NULL)
327     {
328 	/* add the unique element to the buckets list */
329 	ll_add(&(bucket->list), newli);
330 	return NULL;
331     }
332     else
333     {
334 	/* free the stuff we just allocated */
335 	ll_freeitem(newli);
336 	return ((hash_item_uint *)(li->datum))->value;
337     }
338 }
339 
340 /*
341  * void *hash_replace_uint(hash_table *ht, unsigned int key, void *value)
342  *
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
347  */
348 
349 void *
hash_replace_uint(hash_table * ht,unsigned int key,void * value)350 hash_replace_uint(hash_table *ht, unsigned int key, void *value)
351 
352 {
353     bucket_t *bucket;
354     hash_item_uint *hi;
355     llist *ll;
356     llistitem *li;
357     void *result = NULL;
358     unsigned int k1;
359 
360     /* find the bucket */
361     bucket = &(ht->buckets[(key % ht->num_buckets)]);
362 
363     /* walk the list until we find the existing item */
364     ll = &(bucket->list);
365     li = LL_FIRST(ll);
366     while (li != NULL)
367     {
368 	hi = (hash_item_uint *)li->datum;
369 	k1 = hi->key;
370 	if (key == k1)
371 	{
372 	    /* found it: now replace the value with the new one */
373 	    result = hi->value;
374 	    hi->value = value;
375 	    break;
376 	}
377 	li = LL_NEXT(ll, li);
378     }
379 
380     /* if the element wasnt found, add it */
381     if (result == NULL)
382     {
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);
388     }
389 
390     /* return the old value (so it can be freed) */
391     return result;
392 }
393 
394 /*
395  * void *hash_lookup_uint(hash_table *ht, unsigned int key)
396  *
397  * Look up "key" in "ht" and return the associated value.  If "key"
398  * is not found, return NULL.  Key type is unsigned int
399  */
400 
401 void *
hash_lookup_uint(hash_table * ht,unsigned int key)402 hash_lookup_uint(hash_table *ht, unsigned int key)
403 
404 {
405     bucket_t *bucket;
406     llist *ll;
407     llistitem *li;
408     hash_item_uint *h;
409     void *result;
410     unsigned int k1;
411 
412     result = NULL;
413     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
414     {
415 	ll = &(bucket->list);
416 	li = LL_FIRST(ll);
417 	while (li != NULL)
418 	{
419 	    h = (hash_item_uint *)li->datum;
420 	    k1 = h->key;
421 	    if (key == k1)
422 	    {
423 		result = h->value;
424 		break;
425 	    }
426 	    li = LL_NEXT(ll, li);
427 	}
428     }
429     return result;
430 }
431 
432 /*
433  * void *hash_remove_uint(hash_table *ht, unsigned int key)
434  *
435  * Remove the element associated with "key" from the hash table
436  * "ht".  Return the value or NULL if the key was not found.
437  */
438 
439 void *
hash_remove_uint(hash_table * ht,unsigned int key)440 hash_remove_uint(hash_table *ht, unsigned int key)
441 
442 {
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;
450 
451     result = NULL;
452     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
453     {
454 	ll = &(bucket->list);
455 	li = LL_FIRST(ll);
456 	lilast = NULL;
457 	while (li != NULL)
458 	{
459 	    hi = (hash_item_uint *)li->datum;
460 	    k1 = hi->key;
461 	    if (key == k1)
462 	    {
463 		ll_extract(ll, li, lilast);
464 		result = hi->value;
465 		key = hi->key;
466 		;
467 		ll_freeitem(li);
468 		break;
469 	    }
470 	    lilast = li;
471 	    li = LL_NEXT(ll, li);
472 	}
473     }
474     return result;
475 }
476 
477 /*
478  * hash_item_uint *hash_first_uint(hash_table *ht, hash_pos *pos)
479  *
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.
483  */
484 
485 hash_item_uint *
hash_first_uint(hash_table * ht,hash_pos * pos)486 hash_first_uint(hash_table *ht, hash_pos *pos)
487 
488 {
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;
494 
495     /* find the first non-empty bucket */
496     while(pos->hash_bucket->list.count == 0)
497     {
498 	pos->hash_bucket++;
499 	if (++pos->curr >= pos->num_buckets)
500 	{
501 	    return NULL;
502 	}
503     }
504 
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;
508 }
509 
510 
511 /*
512  * hash_item_uint *hash_next_uint(hash_pos *pos)
513  *
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.
517  */
518 
519 hash_item_uint *
hash_next_uint(hash_pos * pos)520 hash_next_uint(hash_pos *pos)
521 
522 {
523     llistitem *li;
524 
525     /* move item to last and check for NULL */
526     if ((pos->ll_last = pos->ll_item) == NULL)
527     {
528 	/* are we really at the end of the hash table? */
529 	if (pos->curr >= pos->num_buckets)
530 	{
531 	    /* yes: return NULL */
532 	    return NULL;
533 	}
534 	/* no: regrab first item in current bucket list (might be NULL) */
535 	li = LL_FIRST(&(pos->hash_bucket->list));
536     }
537     else
538     {
539 	/* get the next item in the llist */
540 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
541     }
542 
543     /* if its NULL we have to find another bucket */
544     while (li == NULL)
545     {
546 	/* locate another bucket */
547 	pos->ll_last = NULL;
548 
549 	/* move to the next one */
550 	pos->hash_bucket++;
551 	if (++pos->curr >= pos->num_buckets)
552 	{
553 	    /* at the end of the hash table */
554 	    pos->ll_item = NULL;
555 	    return NULL;
556 	}
557 
558 	/* get the first element (might be NULL) */
559 	li = LL_FIRST(&(pos->hash_bucket->list));
560     }
561 
562     /* li is the next element to dish out */
563     pos->ll_item = li;
564     return (hash_item_uint *)li->datum;
565 }
566 
567 /*
568  * void *hash_remove_pos_uint(hash_pos *pos)
569  *
570  * Remove the hash table entry pointed to by position marker "pos".
571  * The data from the entry is returned upon success, otherwise NULL.
572  */
573 
574 
575 void *
hash_remove_pos_uint(hash_pos * pos)576 hash_remove_pos_uint(hash_pos *pos)
577 
578 {
579     llistitem *li;
580     void *ans;
581     hash_item_uint *hi;
582 
583     /* sanity checks */
584     if (pos == NULL || pos->ll_last == pos->ll_item)
585     {
586 	return NULL;
587     }
588 
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);
594 
595     /* retain the data */
596     hi = (hash_item_uint *)li->datum;
597     ans = hi->value;
598 
599     ll_freeitem(li);
600 
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;
604 
605     return ans;
606 }
607 
608 
609 
610 /*
611  * void hash_add_pid(hash_table *ht, pid_t key, void *value)
612  *
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
618  */
619 
620 void *
hash_add_pid(hash_table * ht,pid_t key,void * value)621 hash_add_pid(hash_table *ht, pid_t key, void *value)
622 
623 {
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;
631 
632     /* allocate the space we will need */
633     newli = ll_newitem(sizeof(hash_item_pid));
634     hi = (hash_item_pid *)newli->datum;
635 
636     /* fill in the values */
637     hi->key = key;
638     hi->value = value;
639 
640     /* hash to the bucket */
641     bucket = &(ht->buckets[(key % ht->num_buckets)]);
642 
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)
647     {
648 	h = (hash_item_pid *)li->datum;
649 	k1 = h->key;
650 	if (key == k1)
651 	{
652 	    /* found one */
653 	    break;
654 	}
655 	li = LL_NEXT(ll, li);
656     }
657     li = NULL;
658 
659     /* is there already one there? */
660     if (li == NULL)
661     {
662 	/* add the unique element to the buckets list */
663 	ll_add(&(bucket->list), newli);
664 	return NULL;
665     }
666     else
667     {
668 	/* free the stuff we just allocated */
669 	ll_freeitem(newli);
670 	return ((hash_item_pid *)(li->datum))->value;
671     }
672 }
673 
674 /*
675  * void *hash_replace_pid(hash_table *ht, pid_t key, void *value)
676  *
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
681  */
682 
683 void *
hash_replace_pid(hash_table * ht,pid_t key,void * value)684 hash_replace_pid(hash_table *ht, pid_t key, void *value)
685 
686 {
687     bucket_t *bucket;
688     hash_item_pid *hi;
689     llist *ll;
690     llistitem *li;
691     void *result = NULL;
692     pid_t k1;
693 
694     /* find the bucket */
695     bucket = &(ht->buckets[(key % ht->num_buckets)]);
696 
697     /* walk the list until we find the existing item */
698     ll = &(bucket->list);
699     li = LL_FIRST(ll);
700     while (li != NULL)
701     {
702 	hi = (hash_item_pid *)li->datum;
703 	k1 = hi->key;
704 	if (key == k1)
705 	{
706 	    /* found it: now replace the value with the new one */
707 	    result = hi->value;
708 	    hi->value = value;
709 	    break;
710 	}
711 	li = LL_NEXT(ll, li);
712     }
713 
714     /* if the element wasnt found, add it */
715     if (result == NULL)
716     {
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);
722     }
723 
724     /* return the old value (so it can be freed) */
725     return result;
726 }
727 
728 /*
729  * void *hash_lookup_pid(hash_table *ht, pid_t key)
730  *
731  * Look up "key" in "ht" and return the associated value.  If "key"
732  * is not found, return NULL.  Key type is pid_t
733  */
734 
735 void *
hash_lookup_pid(hash_table * ht,pid_t key)736 hash_lookup_pid(hash_table *ht, pid_t key)
737 
738 {
739     bucket_t *bucket;
740     llist *ll;
741     llistitem *li;
742     hash_item_pid *h;
743     void *result;
744     pid_t k1;
745 
746     result = NULL;
747     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
748     {
749 	ll = &(bucket->list);
750 	li = LL_FIRST(ll);
751 	while (li != NULL)
752 	{
753 	    h = (hash_item_pid *)li->datum;
754 	    k1 = h->key;
755 	    if (key == k1)
756 	    {
757 		result = h->value;
758 		break;
759 	    }
760 	    li = LL_NEXT(ll, li);
761 	}
762     }
763     return result;
764 }
765 
766 /*
767  * void *hash_remove_pid(hash_table *ht, pid_t key)
768  *
769  * Remove the element associated with "key" from the hash table
770  * "ht".  Return the value or NULL if the key was not found.
771  */
772 
773 void *
hash_remove_pid(hash_table * ht,pid_t key)774 hash_remove_pid(hash_table *ht, pid_t key)
775 
776 {
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;
784 
785     result = NULL;
786     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
787     {
788 	ll = &(bucket->list);
789 	li = LL_FIRST(ll);
790 	lilast = NULL;
791 	while (li != NULL)
792 	{
793 	    hi = (hash_item_pid *)li->datum;
794 	    k1 = hi->key;
795 	    if (key == k1)
796 	    {
797 		ll_extract(ll, li, lilast);
798 		result = hi->value;
799 		key = hi->key;
800 		;
801 		ll_freeitem(li);
802 		break;
803 	    }
804 	    lilast = li;
805 	    li = LL_NEXT(ll, li);
806 	}
807     }
808     return result;
809 }
810 
811 /*
812  * hash_item_pid *hash_first_pid(hash_table *ht, hash_pos *pos)
813  *
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.
817  */
818 
819 hash_item_pid *
hash_first_pid(hash_table * ht,hash_pos * pos)820 hash_first_pid(hash_table *ht, hash_pos *pos)
821 
822 {
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;
828 
829     /* find the first non-empty bucket */
830     while(pos->hash_bucket->list.count == 0)
831     {
832 	pos->hash_bucket++;
833 	if (++pos->curr >= pos->num_buckets)
834 	{
835 	    return NULL;
836 	}
837     }
838 
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;
842 }
843 
844 
845 /*
846  * hash_item_pid *hash_next_pid(hash_pos *pos)
847  *
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.
851  */
852 
853 hash_item_pid *
hash_next_pid(hash_pos * pos)854 hash_next_pid(hash_pos *pos)
855 
856 {
857     llistitem *li;
858 
859     /* move item to last and check for NULL */
860     if ((pos->ll_last = pos->ll_item) == NULL)
861     {
862 	/* are we really at the end of the hash table? */
863 	if (pos->curr >= pos->num_buckets)
864 	{
865 	    /* yes: return NULL */
866 	    return NULL;
867 	}
868 	/* no: regrab first item in current bucket list (might be NULL) */
869 	li = LL_FIRST(&(pos->hash_bucket->list));
870     }
871     else
872     {
873 	/* get the next item in the llist */
874 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
875     }
876 
877     /* if its NULL we have to find another bucket */
878     while (li == NULL)
879     {
880 	/* locate another bucket */
881 	pos->ll_last = NULL;
882 
883 	/* move to the next one */
884 	pos->hash_bucket++;
885 	if (++pos->curr >= pos->num_buckets)
886 	{
887 	    /* at the end of the hash table */
888 	    pos->ll_item = NULL;
889 	    return NULL;
890 	}
891 
892 	/* get the first element (might be NULL) */
893 	li = LL_FIRST(&(pos->hash_bucket->list));
894     }
895 
896     /* li is the next element to dish out */
897     pos->ll_item = li;
898     return (hash_item_pid *)li->datum;
899 }
900 
901 /*
902  * void *hash_remove_pos_pid(hash_pos *pos)
903  *
904  * Remove the hash table entry pointed to by position marker "pos".
905  * The data from the entry is returned upon success, otherwise NULL.
906  */
907 
908 
909 void *
hash_remove_pos_pid(hash_pos * pos)910 hash_remove_pos_pid(hash_pos *pos)
911 
912 {
913     llistitem *li;
914     void *ans;
915     hash_item_pid *hi;
916 
917     /* sanity checks */
918     if (pos == NULL || pos->ll_last == pos->ll_item)
919     {
920 	return NULL;
921     }
922 
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);
928 
929     /* retain the data */
930     hi = (hash_item_pid *)li->datum;
931     ans = hi->value;
932 
933     /* free up the space */
934     ll_freeitem(li);
935 
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;
939 
940     return ans;
941 }
942 
943 
944 
945 /*
946  * void hash_add_string(hash_table *ht, char * key, void *value)
947  *
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 *
953  */
954 
955 void *
hash_add_string(hash_table * ht,char * key,void * value)956 hash_add_string(hash_table *ht, char * key, void *value)
957 
958 {
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;
966 
967     /* allocate the space we will need */
968     newli = ll_newitem(sizeof(hash_item_string));
969     hi = (hash_item_string *)newli->datum;
970 
971     /* fill in the values */
972     hi->key = estrdup(key);
973     hi->value = value;
974 
975     /* hash to the bucket */
976     bucket = &(ht->buckets[string_hash(ht, key)]);
977 
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)
982     {
983 	h = (hash_item_string *)li->datum;
984 	k1 = h->key;
985 	if (strcmp(key, k1) == 0)
986 	{
987 	    /* found one */
988 	    break;
989 	}
990 	li = LL_NEXT(ll, li);
991     }
992     li = NULL;
993 
994     /* is there already one there? */
995     if (li == NULL)
996     {
997 	/* add the unique element to the buckets list */
998 	ll_add(&(bucket->list), newli);
999 	return NULL;
1000     }
1001     else
1002     {
1003 	/* free the stuff we just allocated */
1004 	ll_freeitem(newli);
1005 	return ((hash_item_string *)(li->datum))->value;
1006     }
1007 }
1008 
1009 /*
1010  * void *hash_replace_string(hash_table *ht, char * key, void *value)
1011  *
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 *
1016  */
1017 
1018 void *
hash_replace_string(hash_table * ht,char * key,void * value)1019 hash_replace_string(hash_table *ht, char * key, void *value)
1020 
1021 {
1022     bucket_t *bucket;
1023     hash_item_string *hi;
1024     llist *ll;
1025     llistitem *li;
1026     void *result = NULL;
1027     char * k1;
1028 
1029     /* find the bucket */
1030     bucket = &(ht->buckets[string_hash(ht, key)]);
1031 
1032     /* walk the list until we find the existing item */
1033     ll = &(bucket->list);
1034     li = LL_FIRST(ll);
1035     while (li != NULL)
1036     {
1037 	hi = (hash_item_string *)li->datum;
1038 	k1 = hi->key;
1039 	if (strcmp(key, k1) == 0)
1040 	{
1041 	    /* found it: now replace the value with the new one */
1042 	    result = hi->value;
1043 	    hi->value = value;
1044 	    break;
1045 	}
1046 	li = LL_NEXT(ll, li);
1047     }
1048 
1049     /* if the element wasnt found, add it */
1050     if (result == NULL)
1051     {
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);
1057     }
1058 
1059     /* return the old value (so it can be freed) */
1060     return result;
1061 }
1062 
1063 /*
1064  * void *hash_lookup_string(hash_table *ht, char * key)
1065  *
1066  * Look up "key" in "ht" and return the associated value.  If "key"
1067  * is not found, return NULL.  Key type is char *
1068  */
1069 
1070 void *
hash_lookup_string(hash_table * ht,char * key)1071 hash_lookup_string(hash_table *ht, char * key)
1072 
1073 {
1074     bucket_t *bucket;
1075     llist *ll;
1076     llistitem *li;
1077     hash_item_string *h;
1078     void *result;
1079     char * k1;
1080 
1081     result = NULL;
1082     if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1083     {
1084 	ll = &(bucket->list);
1085 	li = LL_FIRST(ll);
1086 	while (li != NULL)
1087 	{
1088 	    h = (hash_item_string *)li->datum;
1089 	    k1 = h->key;
1090 	    if (strcmp(key, k1) == 0)
1091 	    {
1092 		result = h->value;
1093 		break;
1094 	    }
1095 	    li = LL_NEXT(ll, li);
1096 	}
1097     }
1098     return result;
1099 }
1100 
1101 /*
1102  * void *hash_remove_string(hash_table *ht, char * key)
1103  *
1104  * Remove the element associated with "key" from the hash table
1105  * "ht".  Return the value or NULL if the key was not found.
1106  */
1107 
1108 void *
hash_remove_string(hash_table * ht,char * key)1109 hash_remove_string(hash_table *ht, char * key)
1110 
1111 {
1112     bucket_t *bucket;
1113     llist *ll;
1114     llistitem *li;
1115     llistitem *lilast;
1116     hash_item_string *hi;
1117     void *result;
1118     char * k1;
1119 
1120     result = NULL;
1121     if ((bucket = &(ht->buckets[string_hash(ht, key)])) != NULL)
1122     {
1123 	ll = &(bucket->list);
1124 	li = LL_FIRST(ll);
1125 	lilast = NULL;
1126 	while (li != NULL)
1127 	{
1128 	    hi = (hash_item_string *)li->datum;
1129 	    k1 = hi->key;
1130 	    if (strcmp(key, k1) == 0)
1131 	    {
1132 		ll_extract(ll, li, lilast);
1133 		result = hi->value;
1134 		key = hi->key;
1135 		free(key);
1136 		ll_freeitem(li);
1137 		break;
1138 	    }
1139 	    lilast = li;
1140 	    li = LL_NEXT(ll, li);
1141 	}
1142     }
1143     return result;
1144 }
1145 
1146 /*
1147  * hash_item_string *hash_first_string(hash_table *ht, hash_pos *pos)
1148  *
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.
1152  */
1153 
1154 hash_item_string *
hash_first_string(hash_table * ht,hash_pos * pos)1155 hash_first_string(hash_table *ht, hash_pos *pos)
1156 
1157 {
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;
1163 
1164     /* find the first non-empty bucket */
1165     while(pos->hash_bucket->list.count == 0)
1166     {
1167 	pos->hash_bucket++;
1168 	if (++pos->curr >= pos->num_buckets)
1169 	{
1170 	    return NULL;
1171 	}
1172     }
1173 
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;
1177 }
1178 
1179 
1180 /*
1181  * hash_item_string *hash_next_string(hash_pos *pos)
1182  *
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.
1186  */
1187 
1188 hash_item_string *
hash_next_string(hash_pos * pos)1189 hash_next_string(hash_pos *pos)
1190 
1191 {
1192     llistitem *li;
1193 
1194     /* move item to last and check for NULL */
1195     if ((pos->ll_last = pos->ll_item) == NULL)
1196     {
1197 	/* are we really at the end of the hash table? */
1198 	if (pos->curr >= pos->num_buckets)
1199 	{
1200 	    /* yes: return NULL */
1201 	    return NULL;
1202 	}
1203 	/* no: regrab first item in current bucket list (might be NULL) */
1204 	li = LL_FIRST(&(pos->hash_bucket->list));
1205     }
1206     else
1207     {
1208 	/* get the next item in the llist */
1209 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1210     }
1211 
1212     /* if its NULL we have to find another bucket */
1213     while (li == NULL)
1214     {
1215 	/* locate another bucket */
1216 	pos->ll_last = NULL;
1217 
1218 	/* move to the next one */
1219 	pos->hash_bucket++;
1220 	if (++pos->curr >= pos->num_buckets)
1221 	{
1222 	    /* at the end of the hash table */
1223 	    pos->ll_item = NULL;
1224 	    return NULL;
1225 	}
1226 
1227 	/* get the first element (might be NULL) */
1228 	li = LL_FIRST(&(pos->hash_bucket->list));
1229     }
1230 
1231     /* li is the next element to dish out */
1232     pos->ll_item = li;
1233     return (hash_item_string *)li->datum;
1234 }
1235 
1236 /*
1237  * void *hash_remove_pos_string(hash_pos *pos)
1238  *
1239  * Remove the hash table entry pointed to by position marker "pos".
1240  * The data from the entry is returned upon success, otherwise NULL.
1241  */
1242 
1243 
1244 void *
hash_remove_pos_string(hash_pos * pos)1245 hash_remove_pos_string(hash_pos *pos)
1246 
1247 {
1248     llistitem *li;
1249     void *ans;
1250     hash_item_string *hi;
1251     char * key;
1252 
1253     /* sanity checks */
1254     if (pos == NULL || pos->ll_last == pos->ll_item)
1255     {
1256 	return NULL;
1257     }
1258 
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);
1264 
1265     /* retain the data */
1266     hi = (hash_item_string *)li->datum;
1267     ans = hi->value;
1268 
1269     /* free up the space */
1270     key = hi->key;
1271     free(key);
1272     ll_freeitem(li);
1273 
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;
1277 
1278     return ans;
1279 }
1280 
1281 
1282 
1283 /*
1284  * void hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1285  *
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
1291  */
1292 
1293 void *
hash_add_pidthr(hash_table * ht,pidthr_t key,void * value)1294 hash_add_pidthr(hash_table *ht, pidthr_t key, void *value)
1295 
1296 {
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;
1304 
1305     /* allocate the space we will need */
1306     newli = ll_newitem(sizeof(hash_item_pidthr));
1307     hi = (hash_item_pidthr *)newli->datum;
1308 
1309     /* fill in the values */
1310     hi->key = key;
1311     hi->value = value;
1312 
1313     /* hash to the bucket */
1314     bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
1315 
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)
1320     {
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))
1324 	{
1325 	    /* found one */
1326 	    break;
1327 	}
1328 	li = LL_NEXT(ll, li);
1329     }
1330     li = NULL;
1331 
1332     /* is there already one there? */
1333     if (li == NULL)
1334     {
1335 	/* add the unique element to the buckets list */
1336 	ll_add(&(bucket->list), newli);
1337 	return NULL;
1338     }
1339     else
1340     {
1341 	/* free the stuff we just allocated */
1342 	ll_freeitem(newli);
1343 	return ((hash_item_pidthr *)(li->datum))->value;
1344     }
1345 }
1346 
1347 /*
1348  * void *hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1349  *
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
1354  */
1355 
1356 void *
hash_replace_pidthr(hash_table * ht,pidthr_t key,void * value)1357 hash_replace_pidthr(hash_table *ht, pidthr_t key, void *value)
1358 
1359 {
1360     bucket_t *bucket;
1361     hash_item_pidthr *hi;
1362     llist *ll;
1363     llistitem *li;
1364     void *result = NULL;
1365     pidthr_t k1;
1366 
1367     /* find the bucket */
1368     bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)]);
1369 
1370     /* walk the list until we find the existing item */
1371     ll = &(bucket->list);
1372     li = LL_FIRST(ll);
1373     while (li != NULL)
1374     {
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))
1378 	{
1379 	    /* found it: now replace the value with the new one */
1380 	    result = hi->value;
1381 	    hi->value = value;
1382 	    break;
1383 	}
1384 	li = LL_NEXT(ll, li);
1385     }
1386 
1387     /* if the element wasnt found, add it */
1388     if (result == NULL)
1389     {
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);
1395     }
1396 
1397     /* return the old value (so it can be freed) */
1398     return result;
1399 }
1400 
1401 /*
1402  * void *hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1403  *
1404  * Look up "key" in "ht" and return the associated value.  If "key"
1405  * is not found, return NULL.  Key type is pidthr_t
1406  */
1407 
1408 void *
hash_lookup_pidthr(hash_table * ht,pidthr_t key)1409 hash_lookup_pidthr(hash_table *ht, pidthr_t key)
1410 
1411 {
1412     bucket_t *bucket;
1413     llist *ll;
1414     llistitem *li;
1415     hash_item_pidthr *h;
1416     void *result;
1417     pidthr_t k1;
1418 
1419     result = NULL;
1420     if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1421     {
1422 	ll = &(bucket->list);
1423 	li = LL_FIRST(ll);
1424 	while (li != NULL)
1425 	{
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))
1429 	    {
1430 		result = h->value;
1431 		break;
1432 	    }
1433 	    li = LL_NEXT(ll, li);
1434 	}
1435     }
1436     return result;
1437 }
1438 
1439 /*
1440  * void *hash_remove_pidthr(hash_table *ht, pidthr_t key)
1441  *
1442  * Remove the element associated with "key" from the hash table
1443  * "ht".  Return the value or NULL if the key was not found.
1444  */
1445 
1446 void *
hash_remove_pidthr(hash_table * ht,pidthr_t key)1447 hash_remove_pidthr(hash_table *ht, pidthr_t key)
1448 
1449 {
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;
1457 
1458     result = NULL;
1459     if ((bucket = &(ht->buckets[((key.k_thr * 10000 + key.k_pid) % ht->num_buckets)])) != NULL)
1460     {
1461 	ll = &(bucket->list);
1462 	li = LL_FIRST(ll);
1463 	lilast = NULL;
1464 	while (li != NULL)
1465 	{
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))
1469 	    {
1470 		ll_extract(ll, li, lilast);
1471 		result = hi->value;
1472 		key = hi->key;
1473 		;
1474 		ll_freeitem(li);
1475 		break;
1476 	    }
1477 	    lilast = li;
1478 	    li = LL_NEXT(ll, li);
1479 	}
1480     }
1481     return result;
1482 }
1483 
1484 /*
1485  * hash_item_pidthr *hash_first_pidthr(hash_table *ht, hash_pos *pos)
1486  *
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.
1490  */
1491 
1492 hash_item_pidthr *
hash_first_pidthr(hash_table * ht,hash_pos * pos)1493 hash_first_pidthr(hash_table *ht, hash_pos *pos)
1494 
1495 {
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;
1501 
1502     /* find the first non-empty bucket */
1503     while(pos->hash_bucket->list.count == 0)
1504     {
1505 	pos->hash_bucket++;
1506 	if (++pos->curr >= pos->num_buckets)
1507 	{
1508 	    return NULL;
1509 	}
1510     }
1511 
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;
1515 }
1516 
1517 
1518 /*
1519  * hash_item_pidthr *hash_next_pidthr(hash_pos *pos)
1520  *
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.
1524  */
1525 
1526 hash_item_pidthr *
hash_next_pidthr(hash_pos * pos)1527 hash_next_pidthr(hash_pos *pos)
1528 
1529 {
1530     llistitem *li;
1531 
1532     /* move item to last and check for NULL */
1533     if ((pos->ll_last = pos->ll_item) == NULL)
1534     {
1535 	/* are we really at the end of the hash table? */
1536 	if (pos->curr >= pos->num_buckets)
1537 	{
1538 	    /* yes: return NULL */
1539 	    return NULL;
1540 	}
1541 	/* no: regrab first item in current bucket list (might be NULL) */
1542 	li = LL_FIRST(&(pos->hash_bucket->list));
1543     }
1544     else
1545     {
1546 	/* get the next item in the llist */
1547 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1548     }
1549 
1550     /* if its NULL we have to find another bucket */
1551     while (li == NULL)
1552     {
1553 	/* locate another bucket */
1554 	pos->ll_last = NULL;
1555 
1556 	/* move to the next one */
1557 	pos->hash_bucket++;
1558 	if (++pos->curr >= pos->num_buckets)
1559 	{
1560 	    /* at the end of the hash table */
1561 	    pos->ll_item = NULL;
1562 	    return NULL;
1563 	}
1564 
1565 	/* get the first element (might be NULL) */
1566 	li = LL_FIRST(&(pos->hash_bucket->list));
1567     }
1568 
1569     /* li is the next element to dish out */
1570     pos->ll_item = li;
1571     return (hash_item_pidthr *)li->datum;
1572 }
1573 
1574 /*
1575  * void *hash_remove_pos_pidthr(hash_pos *pos)
1576  *
1577  * Remove the hash table entry pointed to by position marker "pos".
1578  * The data from the entry is returned upon success, otherwise NULL.
1579  */
1580 
1581 
1582 void *
hash_remove_pos_pidthr(hash_pos * pos)1583 hash_remove_pos_pidthr(hash_pos *pos)
1584 
1585 {
1586     llistitem *li;
1587     void *ans;
1588     hash_item_pidthr *hi;
1589 
1590     /* sanity checks */
1591     if (pos == NULL || pos->ll_last == pos->ll_item)
1592     {
1593 	return NULL;
1594     }
1595 
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);
1601 
1602     /* retain the data */
1603     hi = (hash_item_pidthr *)li->datum;
1604     ans = hi->value;
1605 
1606     /* free up the space */
1607     ll_freeitem(li);
1608 
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;
1612 
1613     return ans;
1614 }
1615 
1616 #if HAVE_LWPID_T
1617 
1618 
1619 /*
1620  * void hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1621  *
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
1627  */
1628 
1629 void *
hash_add_lwpid(hash_table * ht,lwpid_t key,void * value)1630 hash_add_lwpid(hash_table *ht, lwpid_t key, void *value)
1631 
1632 {
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;
1640 
1641     /* allocate the space we will need */
1642     newli = ll_newitem(sizeof(hash_item_lwpid));
1643     hi = (hash_item_lwpid *)newli->datum;
1644 
1645     /* fill in the values */
1646     hi->key = key;
1647     hi->value = value;
1648 
1649     /* hash to the bucket */
1650     bucket = &(ht->buckets[(key % ht->num_buckets)]);
1651 
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)
1656     {
1657 	h = (hash_item_lwpid *)li->datum;
1658 	k1 = h->key;
1659 	if (key == k1)
1660 	{
1661 	    /* found one */
1662 	    break;
1663 	}
1664 	li = LL_NEXT(ll, li);
1665     }
1666     li = NULL;
1667 
1668     /* is there already one there? */
1669     if (li == NULL)
1670     {
1671 	/* add the unique element to the buckets list */
1672 	ll_add(&(bucket->list), newli);
1673 	return NULL;
1674     }
1675     else
1676     {
1677 	/* free the stuff we just allocated */
1678 	ll_freeitem(newli);
1679 	return ((hash_item_lwpid *)(li->datum))->value;
1680     }
1681 }
1682 
1683 /*
1684  * void *hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1685  *
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
1690  */
1691 
1692 void *
hash_replace_lwpid(hash_table * ht,lwpid_t key,void * value)1693 hash_replace_lwpid(hash_table *ht, lwpid_t key, void *value)
1694 
1695 {
1696     bucket_t *bucket;
1697     hash_item_lwpid *hi;
1698     llist *ll;
1699     llistitem *li;
1700     void *result = NULL;
1701     lwpid_t k1;
1702 
1703     /* find the bucket */
1704     bucket = &(ht->buckets[(key % ht->num_buckets)]);
1705 
1706     /* walk the list until we find the existing item */
1707     ll = &(bucket->list);
1708     li = LL_FIRST(ll);
1709     while (li != NULL)
1710     {
1711 	hi = (hash_item_lwpid *)li->datum;
1712 	k1 = hi->key;
1713 	if (key == k1)
1714 	{
1715 	    /* found it: now replace the value with the new one */
1716 	    result = hi->value;
1717 	    hi->value = value;
1718 	    break;
1719 	}
1720 	li = LL_NEXT(ll, li);
1721     }
1722 
1723     /* if the element wasnt found, add it */
1724     if (result == NULL)
1725     {
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);
1731     }
1732 
1733     /* return the old value (so it can be freed) */
1734     return result;
1735 }
1736 
1737 /*
1738  * void *hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1739  *
1740  * Look up "key" in "ht" and return the associated value.  If "key"
1741  * is not found, return NULL.  Key type is lwpid_t
1742  */
1743 
1744 void *
hash_lookup_lwpid(hash_table * ht,lwpid_t key)1745 hash_lookup_lwpid(hash_table *ht, lwpid_t key)
1746 
1747 {
1748     bucket_t *bucket;
1749     llist *ll;
1750     llistitem *li;
1751     hash_item_lwpid *h;
1752     void *result;
1753     lwpid_t k1;
1754 
1755     result = NULL;
1756     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1757     {
1758 	ll = &(bucket->list);
1759 	li = LL_FIRST(ll);
1760 	while (li != NULL)
1761 	{
1762 	    h = (hash_item_lwpid *)li->datum;
1763 	    k1 = h->key;
1764 	    if (key == k1)
1765 	    {
1766 		result = h->value;
1767 		break;
1768 	    }
1769 	    li = LL_NEXT(ll, li);
1770 	}
1771     }
1772     return result;
1773 }
1774 
1775 /*
1776  * void *hash_remove_lwpid(hash_table *ht, lwpid_t key)
1777  *
1778  * Remove the element associated with "key" from the hash table
1779  * "ht".  Return the value or NULL if the key was not found.
1780  */
1781 
1782 void *
hash_remove_lwpid(hash_table * ht,lwpid_t key)1783 hash_remove_lwpid(hash_table *ht, lwpid_t key)
1784 
1785 {
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;
1793 
1794     result = NULL;
1795     if ((bucket = &(ht->buckets[(key % ht->num_buckets)])) != NULL)
1796     {
1797 	ll = &(bucket->list);
1798 	li = LL_FIRST(ll);
1799 	lilast = NULL;
1800 	while (li != NULL)
1801 	{
1802 	    hi = (hash_item_lwpid *)li->datum;
1803 	    k1 = hi->key;
1804 	    if (key == k1)
1805 	    {
1806 		ll_extract(ll, li, lilast);
1807 		result = hi->value;
1808 		key = hi->key;
1809 		;
1810 		ll_freeitem(li);
1811 		break;
1812 	    }
1813 	    lilast = li;
1814 	    li = LL_NEXT(ll, li);
1815 	}
1816     }
1817     return result;
1818 }
1819 
1820 /*
1821  * hash_item_lwpid *hash_first_lwpid(hash_table *ht, hash_pos *pos)
1822  *
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.
1826  */
1827 
1828 hash_item_lwpid *
hash_first_lwpid(hash_table * ht,hash_pos * pos)1829 hash_first_lwpid(hash_table *ht, hash_pos *pos)
1830 
1831 {
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;
1837 
1838     /* find the first non-empty bucket */
1839     while(pos->hash_bucket->list.count == 0)
1840     {
1841 	pos->hash_bucket++;
1842 	if (++pos->curr >= pos->num_buckets)
1843 	{
1844 	    return NULL;
1845 	}
1846     }
1847 
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;
1851 }
1852 
1853 
1854 /*
1855  * hash_item_lwpid *hash_next_lwpid(hash_pos *pos)
1856  *
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.
1860  */
1861 
1862 hash_item_lwpid *
hash_next_lwpid(hash_pos * pos)1863 hash_next_lwpid(hash_pos *pos)
1864 
1865 {
1866     llistitem *li;
1867 
1868     /* move item to last and check for NULL */
1869     if ((pos->ll_last = pos->ll_item) == NULL)
1870     {
1871 	/* are we really at the end of the hash table? */
1872 	if (pos->curr >= pos->num_buckets)
1873 	{
1874 	    /* yes: return NULL */
1875 	    return NULL;
1876 	}
1877 	/* no: regrab first item in current bucket list (might be NULL) */
1878 	li = LL_FIRST(&(pos->hash_bucket->list));
1879     }
1880     else
1881     {
1882 	/* get the next item in the llist */
1883 	li = LL_NEXT(&(pos->hash_bucket->list), pos->ll_item);
1884     }
1885 
1886     /* if its NULL we have to find another bucket */
1887     while (li == NULL)
1888     {
1889 	/* locate another bucket */
1890 	pos->ll_last = NULL;
1891 
1892 	/* move to the next one */
1893 	pos->hash_bucket++;
1894 	if (++pos->curr >= pos->num_buckets)
1895 	{
1896 	    /* at the end of the hash table */
1897 	    pos->ll_item = NULL;
1898 	    return NULL;
1899 	}
1900 
1901 	/* get the first element (might be NULL) */
1902 	li = LL_FIRST(&(pos->hash_bucket->list));
1903     }
1904 
1905     /* li is the next element to dish out */
1906     pos->ll_item = li;
1907     return (hash_item_lwpid *)li->datum;
1908 }
1909 
1910 /*
1911  * void *hash_remove_pos_lwpid(hash_pos *pos)
1912  *
1913  * Remove the hash table entry pointed to by position marker "pos".
1914  * The data from the entry is returned upon success, otherwise NULL.
1915  */
1916 
1917 
1918 void *
hash_remove_pos_lwpid(hash_pos * pos)1919 hash_remove_pos_lwpid(hash_pos *pos)
1920 
1921 {
1922     llistitem *li;
1923     void *ans;
1924     hash_item_lwpid *hi;
1925 
1926     /* sanity checks */
1927     if (pos == NULL || pos->ll_last == pos->ll_item)
1928     {
1929 	return NULL;
1930     }
1931 
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);
1937 
1938     /* retain the data */
1939     hi = (hash_item_lwpid *)li->datum;
1940     ans = hi->value;
1941 
1942     /* free up the space */
1943     ll_freeitem(li);
1944 
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;
1948 
1949     return ans;
1950 }
1951 
1952 #endif
1953