217 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			5.5 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
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 $
 | 
						|
*/
 | 
						|
#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 it */
 | 
						|
__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;
 | 
						|
}
 | 
						|
 |