-
Henrik (Grubba) Grubbström authored
Rev: src/array.c:1.83 Rev: src/backend.c:1.54 Rev: src/docode.c:1.78 Rev: src/encode.c:1.66 Rev: src/error.c:1.60 Rev: src/error.h:1.48 Rev: src/errors.h:1.12 Rev: src/fsort.c:1.14 Rev: src/hashtable.c:1.7 Rev: src/main.c:1.96 Rev: src/pike_memory.h:1.21 Rev: src/pike_types.c:1.133 Rev: src/pike_types.h:1.43
Henrik (Grubba) Grubbström authoredRev: src/array.c:1.83 Rev: src/backend.c:1.54 Rev: src/docode.c:1.78 Rev: src/encode.c:1.66 Rev: src/error.c:1.60 Rev: src/error.h:1.48 Rev: src/errors.h:1.12 Rev: src/fsort.c:1.14 Rev: src/hashtable.c:1.7 Rev: src/main.c:1.96 Rev: src/pike_memory.h:1.21 Rev: src/pike_types.c:1.133 Rev: src/pike_types.h:1.43
hashtable.c 3.59 KiB
/*\
||| This file a part of Pike, and is copyright by Fredrik Hubinette
||| Pike is distributed as GPL (General Public License)
||| See the files COPYING and DISCLAIMER for more information.
\*/
/**/
#include "global.h"
#include "hashtable.h"
#include "stralloc.h"
#include "stuff.h"
#include "error.h"
RCSID("$Id: hashtable.c,v 1.7 2000/08/15 16:03:48 grubba Exp $");
static size_t gobble(struct pike_string *s)
{
size_t i;
i=my_hash_string(s);
i+=i >> 3;
i+=i >> 7;
i+=i >> 12;
return i;
}
/*
* Search hash for a specific string.
*/
struct hash_entry *hash_lookup(struct hash_table *h, struct pike_string *s)
{
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
*/
struct hash_table *create_hash_table(void)
{
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 PIKE_DEBUG
if( 1 << my_log2(size) != size)
fatal("Size is not a power 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 PIKE_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);
}