| 
									
										
										
										
											2006-06-04 19:02:07 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  | Copyright (C) 2004,2005,2006 (Nuno A. Fonseca) <nuno.fonseca@gmail.com> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This program is free software; you can redistribute it and/or  | 
					
						
							|  |  |  | modify it under the terms of the GNU General Public License  | 
					
						
							|  |  |  | as published by the Free Software Foundation; either  | 
					
						
							|  |  |  | version 2 of the License, or (at your option) any later  | 
					
						
							|  |  |  | version. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  | GNU General Public License for more details. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  | along with this program; if not, write to the Free Software | 
					
						
							|  |  |  | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Last rev: $Id: hash.c,v 1.2 2006-06-04 19:02:07 nunofonseca Exp $ | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2006-06-02 04:16:31 +00:00
										 |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "hash.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define BUCKET(table,i) table->buckets[i]
 | 
					
						
							|  |  |  | #define HASHSIZE(table) table->size
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int mhash(hashtable,ulong); | 
					
						
							|  |  |  | static hashnode* hash_lookup(hashtable,ulong); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static hashnode* hash_lookup(hashtable table,ulong  key){ | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   table->last_node = BUCKET(table,mhash(table,key)); /* set a pointer to the first bucket */ | 
					
						
							|  |  |  |   while ( table->last_node != NULL ) { | 
					
						
							|  |  |  |     if( table->last_node->value==key) return table->last_node; | 
					
						
							|  |  |  |     table->last_node = table->last_node->next; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | __ptr_t get_next_object(hashtable table,ulong key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   if(table->last_node==NULL) | 
					
						
							|  |  |  |     return NULL;  | 
					
						
							|  |  |  |   table->last_node = table->last_node->next; | 
					
						
							|  |  |  |   while ( table->last_node != NULL ) { | 
					
						
							|  |  |  |      if( table->last_node->value==key) return table->last_node->obj; | 
					
						
							|  |  |  |      table->last_node = table->last_node->next; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* removes the element with key 'key' and returns the object stored on him */ | 
					
						
							|  |  |  | __ptr_t delete(hashtable table,ulong key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   __ptr_t obj; | 
					
						
							|  |  |  |   hashnode *b,*prev=NULL; | 
					
						
							|  |  |  |   int c=mhash(table,key); | 
					
						
							|  |  |  |   b=BUCKET(table,c); /* set a pointer to the first bucket */ | 
					
						
							|  |  |  |   while( b!=NULL) { | 
					
						
							|  |  |  |     if( b->value==key){ | 
					
						
							|  |  |  |       obj=b->obj; | 
					
						
							|  |  |  |       if(prev==NULL) /* first element */ | 
					
						
							|  |  |  | 	BUCKET(table,c)=b->next; | 
					
						
							|  |  |  |       else  | 
					
						
							|  |  |  | 	prev->next=b->next; | 
					
						
							|  |  |  |       free(b); | 
					
						
							|  |  |  |       table->n_entries--; | 
					
						
							|  |  |  |       return obj; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     prev = b; | 
					
						
							|  |  |  |     b = b->next; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  |   return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | __ptr_t replace_object(hashtable table,ulong  key,__ptr_t newobj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   __ptr_t old; | 
					
						
							|  |  |  |   hashnode *b=hash_lookup(table,key);  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if(b==NULL)return NULL; | 
					
						
							|  |  |  |   old=b->obj; | 
					
						
							|  |  |  |   b->obj=newobj; | 
					
						
							|  |  |  |   return old;   | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* looks a 'bucket' in the hashing table whith 'key' and return the
 | 
					
						
							|  |  |  |  pointer to the object stored in that bucket or NULL if no bucket is found */  | 
					
						
							|  |  |  | __ptr_t get_object(hashtable table,ulong key){ | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |    hashnode *b=hash_lookup(table,key);  | 
					
						
							|  |  |  |    if(b==NULL) | 
					
						
							|  |  |  |        return NULL; | 
					
						
							|  |  |  |    return b->obj;  | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Allocates space to a new hash table */ | 
					
						
							|  |  |  | hashtable new_hashtable(ulong hashsize) { | 
					
						
							|  |  |  |   hashtable new; | 
					
						
							|  |  |  |   register int i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   if( (new = (hashtable)malloc(sizeof(struct hashtable_s)))==NULL) return NULL; | 
					
						
							|  |  |  |    | 
					
						
							|  |  |  |   if( (new->buckets = (hashnode**)malloc(sizeof(hashnode*)*hashsize))==NULL)  | 
					
						
							|  |  |  |      return NULL; | 
					
						
							|  |  |  |   new->size=hashsize; | 
					
						
							|  |  |  |   new->last_bucket=0; | 
					
						
							|  |  |  |   new->last_node=NULL; | 
					
						
							|  |  |  |   new->n_entries=0; | 
					
						
							|  |  |  |   for(i=0;i<hashsize;++i) BUCKET(new,i) = NULL; | 
					
						
							|  |  |  |   return new; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* A very simple hashing function */ | 
					
						
							|  |  |  | static int mhash(hashtable table,ulong key) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   return (int)(key%HASHSIZE(table)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* inserts a new element in the hash table*/ | 
					
						
							|  |  |  | int insere(hashtable table,ulong key,__ptr_t obj) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    int ind; | 
					
						
							|  |  |  |    hashnode *new; | 
					
						
							|  |  |  |    if((new=(hashnode *)malloc(sizeof(hashnode)))==NULL) return -1; | 
					
						
							|  |  |  |    ind=mhash(table,key); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |    new->next = BUCKET(table,ind); | 
					
						
							|  |  |  |    new->value=key; | 
					
						
							|  |  |  |    new->obj=obj; | 
					
						
							|  |  |  |    BUCKET(table,ind)=new; | 
					
						
							|  |  |  |    table->n_entries++; | 
					
						
							|  |  |  |    return 1; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void free_hashtable(hashtable table) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |    register int i; | 
					
						
							|  |  |  |    hashnode *n,*tmp; | 
					
						
							|  |  |  |    //fprintf(stderr,"free_hashtable\n");fflush(stderr);
 | 
					
						
							|  |  |  |    if (table==NULL) return; | 
					
						
							|  |  |  |    for(i=0;i<HASHSIZE(table);++i) { | 
					
						
							|  |  |  |       n=BUCKET(table,i); | 
					
						
							|  |  |  |       while(n!=NULL) { | 
					
						
							|  |  |  |          tmp=n; | 
					
						
							|  |  |  |          n=n->next; | 
					
						
							|  |  |  |          free(tmp); | 
					
						
							|  |  |  |       }       | 
					
						
							|  |  |  |    } | 
					
						
							|  |  |  |    free(table->buckets); | 
					
						
							|  |  |  |    free(table); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*********************************************************************************/ | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Returns all objects stored in a basket by making successive calls | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | void init_hash_traversal(hashtable table) { | 
					
						
							|  |  |  |   table->last_bucket=0; | 
					
						
							|  |  |  |   table->last_node=NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Returns all objects stored in a basket by making successive calls | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | __ptr_t next_hash_object(hashtable table) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // first time....
 | 
					
						
							|  |  |  |   if( table->last_bucket>=HASHSIZE(table))  | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |   if( table->last_node==NULL ) { | 
					
						
							|  |  |  |     // find bucket
 | 
					
						
							|  |  |  |     // find next bucket
 | 
					
						
							|  |  |  |     while ( table->last_node == NULL && table->last_bucket+1<HASHSIZE(table)) { | 
					
						
							|  |  |  |       ++table->last_bucket; | 
					
						
							|  |  |  |       table->last_node = BUCKET(table,table->last_bucket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (table->last_node==NULL) | 
					
						
							|  |  |  |       return NULL; | 
					
						
							|  |  |  |     return table->last_node->obj; | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   // Next in bucket
 | 
					
						
							|  |  |  |   table->last_node=table->last_node->next; | 
					
						
							|  |  |  |   if (table->last_node==NULL) return next_hash_object(table); | 
					
						
							|  |  |  |   return table->last_node->obj; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*
 | 
					
						
							|  |  |  |  * Returns all hash nodes stored in a basket by making successive calls | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | __ptr_t next_hashnode(hashtable table) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |   // first time....
 | 
					
						
							|  |  |  |   if( table->last_bucket>=HASHSIZE(table))  | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  |   if( table->last_node==NULL ) { | 
					
						
							|  |  |  |     // find bucket
 | 
					
						
							|  |  |  |     // find next bucket
 | 
					
						
							|  |  |  |     while ( table->last_node == NULL && table->last_bucket+1<HASHSIZE(table)) { | 
					
						
							|  |  |  |       ++table->last_bucket; | 
					
						
							|  |  |  |       table->last_node = BUCKET(table,table->last_bucket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (table->last_node==NULL) | 
					
						
							|  |  |  |       return NULL; | 
					
						
							|  |  |  |     return table->last_node; | 
					
						
							|  |  |  |   }  | 
					
						
							|  |  |  |   // Next in bucket
 | 
					
						
							|  |  |  |   table->last_node=table->last_node->next; | 
					
						
							|  |  |  |   if (table->last_node==NULL) return next_hashnode(table); | 
					
						
							|  |  |  |   return table->last_node; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 |