cb22561995-10-11Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
cb22561995-10-11Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/
5c8e891995-10-29Fredrik Hübinette (Hubbe) #include "global.h"
5267b71995-08-09Fredrik Hübinette (Hubbe) #include "hashtable.h" #include "stralloc.h" #include "stuff.h" #include "error.h"
24ddc71998-03-28Henrik Grubbström (Grubba) RCSID("$Id: hashtable.c,v 1.4 1998/03/28 15:14:56 grubba Exp $");
06983f1996-09-22Fredrik Hübinette (Hubbe) static unsigned INT32 gobble(struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) { unsigned INT32 i; i=my_hash_string(s); i+=i >> 3; i+=i >> 7; i+=i >> 12; return i; } /* * Search hash for a specific string. */
06983f1996-09-22Fredrik Hübinette (Hubbe) struct hash_entry *hash_lookup(struct hash_table *h, struct pike_string *s)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct hash_entry *e, **prev, **base; if(!h) return 0; base = prev = h->htable + (gobble(s) & h->mask); for( ;(e = *prev); prev= &e->next) { if(s == e->s) { /* Teleport entry to beginning of line */ *prev = e->next; e->next = *base; *base = e; /* Entry arrives in a puff of smoke. */ return e; } } return 0; } /* * We want to keep the order of the hash chain, as it has been carefully * built up to be fast. */ static void rehash_list_backwards(struct hash_table *h, struct hash_entry *n) { struct hash_entry **base; if(!n) return; rehash_list_backwards(h,n->next); base=h->htable + (gobble(n->s) & h->mask); n->next = *base; *base=n; } /* * create a new, empty hashable */
be478c1997-08-30Henrik Grubbström (Grubba) struct hash_table *create_hash_table(void)
5267b71995-08-09Fredrik Hübinette (Hubbe) { struct hash_table *new; new=(struct hash_table *)calloc(1,sizeof(struct hash_table)+ (NEW_HASHTABLE_SIZE-1)*sizeof(struct hash_entry *)); new->entries=0; new->mask=NEW_HASHTABLE_SIZE-1; return new; } /* * rehash - ugh */ struct hash_table *hash_rehash(struct hash_table *h,int size) { struct hash_table *new; int e; #ifdef DEBUG if( 1 << my_log2(size) != size) fatal("Size is not a exponent of two!\n"); #endif new=(struct hash_table *)calloc(1,sizeof(struct hash_table)+ (size-1)*sizeof(struct hash_entry *)); new->mask = size - 1; new->entries = h->entries; for(e=0; e<=h->mask; e++) rehash_list_backwards(new,h->htable[e]); free((char *)h); return new; } /* * insert a newly created hash entry on it's rightful place in the * hashtable */ struct hash_table *hash_insert(struct hash_table *h, struct hash_entry *s) { struct hash_entry **base; if(!h) h=create_hash_table(); if(h->entries > AVERAGE_HASH_LENGTH * 2 * h->mask) h=hash_rehash(h,(h->mask+1) * 2); base = h->htable + (gobble(s->s) & h->mask); s->next = *base; *base = s; h->entries++; return h; } /* * unlink an entry from an hash table */ struct hash_table *hash_unlink(struct hash_table *h, struct hash_entry *s) { struct hash_entry **prev,*e; prev = h->htable + (gobble(s->s) & h->mask); for(;( e=*prev ); prev=&e->next) { if(e==s) { *prev = e->next; h->entries--; if(h->mask > NEW_HASHTABLE_SIZE && h->entries < AVERAGE_HASH_LENGTH / 2 * h->mask) h=hash_rehash(h,(h->mask+1) / 2); return h; } } #ifdef DEBUG fatal("hash_entry not in hashtable\n"); #endif return h; } void map_hashtable(struct hash_table *h, void (*fun)(struct hash_entry *)) { INT32 e; struct hash_entry *i, *n; for(e=0;e<=h->mask;e++) { for(i=h->htable[e];i;i=n) { n=i->next; fun(i); } } } void free_hashtable(struct hash_table *h, void (*free_entry)(struct hash_entry *)) { INT32 e; struct hash_entry *i, *n; for(e=0;e<=h->mask;e++) { for(i=h->htable[e];i;i=n) { n=i->next; free_string(i->s); if(free_entry) free_entry(i); else free((char *)i); } } free((char *)h); }