Main Page   Compound List   File List   Compound Members   File Members  

hash.c

00001 /*
00002 GOCR Copyright (C) 2000  Joerg Schulenburg Joerg.Schulenburg@physik.uni-magdeburg.de 
00003 GOCR API Copyright (C) 2001 Bruno Barberi Gnecco <brunobg@sourceforge.net>
00004 
00005 This program is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU General Public License
00007 as published by the Free Software Foundation; either version 2
00008 of the License, or (at your option) any later version.
00009 
00010 This program is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 GNU General Public License for more details.
00014 
00015 You should have received a copy of the GNU General Public License
00016 along with this program; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00018 
00019 */
00020 
00021 #include "hash.h"
00022 #include <string.h>
00023 
00024 #ifndef CHAIN
00025 static const hashItem deletednode = { NULL, NULL };
00026 #endif
00027 
00028 /* internal Hash generator */
00029 static int hash ( char *key ) {
00030   unsigned int hash = 0;
00031 
00032   while ( *key ) {
00033     /* this algorithm is from Bob Stout's Snippets collection, and was written
00034       by Jerry Coffin and HenkJan Wolthuis and released under public domain */
00035     hash ^= *key++;
00036     hash <<= 1;
00037   }
00038 
00039   return hash;
00040 }
00041 
00042 /* Given a key, returns the data associated with it. */
00043 void *hash_data ( HashTable *t, char *key ) {
00044   unsigned int index, initial;
00045 #ifdef CHAIN
00046   hashItem *h;
00047 #endif
00048   
00049   if ( t == NULL || t->size <= 0 || t->hash_func == NULL || key == NULL )
00050     return NULL;
00051 
00052   index = t->hash_func(key) % t->size;
00053 
00054 #ifdef CHAIN
00055   for ( h = t->item[index]; h != NULL; h = h->next )
00056     if ( strcmp(key, h->key) == 0 )
00057       return h->data;
00058 #else
00059   while ( t->item[index] ) {
00060     if ( t->item[index]->key == NULL || strcmp(key, t->item[index]->key) != 0 ) {
00061       index = (index+1)%t->size;
00062       if ( index == initial ) { /* not found */
00063         return NULL;
00064       }
00065     }
00066     else { /* found */
00067       return t->item[index]->data;
00068     }
00069   }
00070 #endif
00071 
00072   return NULL;
00073 }
00074 
00075 /* Deletes the entry associated with key. Returns a pointer to the data 
00076 structure, which is not freed. */
00077 void *hash_del ( HashTable *t, char *key ) {
00078   unsigned int initial, index;
00079   void *data;
00080 #ifdef CHAIN
00081   hashItem *h, *last = NULL;
00082 #endif
00083   
00084   if ( t == NULL || t->size <= 0 || t->hash_func == NULL || key == NULL )
00085     return NULL;
00086 
00087   initial = index = t->hash_func(key) % t->size;
00088 
00089 #ifdef CHAIN
00090   for ( h = t->item[index]; h != NULL; h = h->next ) {
00091     if ( strcmp(key, h->key) == 0 ) {
00092       /* fix list */
00093       if ( last )
00094         last->next = h->next;
00095       else /* is first item */
00096         t->item[index] = h->next;
00097       free(h->key);
00098       data = h->data;
00099       free(h);
00100       h = NULL;
00101       return data;
00102     }
00103     last = h;
00104   }
00105 #else
00106   while ( t->item[index] ) {
00107     if ( strcmp(key, t->item[index]->key) != 0 ) {
00108       index = (index+1)%t->size;
00109       if ( index == initial ) { /* not found */
00110         return NULL;
00111       }
00112     }
00113     else { /* found */
00114       free(t->item[index]->key);
00115       data = t->item[index]->data;
00116       free(t->item[index]);
00117       t->item[index] = &deletednode;
00118       return data;
00119     }
00120   }
00121 #endif
00122 
00123   return NULL;
00124 }
00125 
00126 /* Frees the hash table contents (but not the table). If free_func is not NULL,
00127 it's called for every data stored in the table */
00128 int hash_free ( HashTable *t, void (*free_func)(void *) ) {
00129   int i;
00130 #ifdef CHAIN
00131   hashItem *h, *next = NULL;
00132 #endif
00133 
00134   if ( t == NULL || t->size <= 0 || t->hash_func == NULL )
00135     return -1;
00136 
00137   for ( i = 0; i < t->size; i++ ) {
00138 #ifdef CHAIN
00139     for ( h = t->item[i]; h != NULL; h = next ) {
00140       next = h->next;
00141       if ( h->key )
00142         free(h->key);
00143       if ( free_func )
00144         free_func(h->data);
00145       free(h);
00146     }
00147 #else
00148     if ( t->item[i] != NULL && t->item[i] != &deletednode ) {
00149       if ( t->item[i]->key )
00150         free(t->item[i]->key);
00151       if ( free_func )
00152         free_func(t->item[i]->data);
00153       free(t->item[i]);
00154     }
00155 #endif
00156   }
00157 
00158   t->size = 0;
00159   return 0;
00160 }
00161 
00162 /* Initialize a hash table, with size entries, using hash_func as the hash
00163 generator func. If t is NULL, the function automaticall mallocs memory for it.
00164 If hash_func is NULL, the default internal is used. Returns -1 on error, 0 if
00165 OK. */
00166 int hash_init ( HashTable *t, int size, int (* hash_func)(char *) ) {
00167   if ( size <= 0 )
00168     return -1;
00169 
00170   if ( t == NULL ) {
00171     t = (HashTable *)malloc(sizeof(HashTable));
00172     if ( t == NULL )
00173       return -1;
00174   }
00175 
00176   t->size = size;
00177   t->item = (hashItem **)malloc(sizeof(hashItem *)*size);
00178   if ( t->item == NULL ) {
00179     t->size = 0;
00180     return -1;
00181   }
00182   for ( size-- ; size >= 0; size-- )
00183     t->item[size] == NULL;
00184 
00185   if ( hash_func )
00186     t->hash_func = hash_func;
00187   else
00188     t->hash_func = hash;
00189 
00190   return 0;
00191 }
00192 
00193 /* Inserts a new entry in table t, with key key, which will contain data.
00194 Returns -2 if data already exists, -1 on error, else the hash. */
00195 int hash_insert ( HashTable *t, char *key, void *data ) {
00196   unsigned int index, initial;
00197 #ifdef CHAIN
00198   hashItem *h;
00199 #endif
00200 
00201   if ( t == NULL || t->size <= 0 || t->hash_func == NULL || key == NULL )
00202     return -1;
00203 
00204   initial = index = t->hash_func(key) % t->size;
00205 
00206   /* if index is free, fill it */
00207   if ( t->item[index] == NULL ) { 
00208     t->item[index] = (hashItem *)malloc(sizeof(hashItem));
00209     if ( t->item[index] == NULL )
00210       return -1;
00211 
00212     t->item[index]->key  = strdup(key);
00213     t->item[index]->data = data;
00214 #ifdef CHAIN
00215     t->item[index]->next = NULL;
00216 #endif
00217 
00218     return index;
00219   }
00220 
00221 #ifdef CHAIN
00222   /* no, then find if the key already exists, and reach the last link */
00223   for ( h = t->item[index]; h->next != NULL; h = h->next )
00224     if ( strcmp(key, h->key) == 0 )
00225       return -2;
00226 
00227   h->next = (hashItem *)malloc(sizeof(hashItem));
00228   if ( h->next == NULL )
00229     return -1;
00230 
00231   h->next->key  = strdup(key);
00232   h->next->data = data;
00233   h->next->next = NULL;
00234 #else
00235   /* no, then find next one free. Using linear probing. */
00236   while ( t->item[index] != NULL ) {
00237     index = (index+1) % t->size;
00238     if ( index == initial ) /* full */
00239       return -1;
00240     if ( strcmp(key, t->item[index]->key) == 0 )
00241       return -2;
00242   }
00243 
00244   t->item[index] = (hashItem *)malloc(sizeof(hashItem));
00245   if ( t->item[index] == NULL )
00246     return -1;
00247 
00248   t->item[index]->key  = strdup(key);
00249   t->item[index]->data = data;
00250 #endif
00251 
00252   return index;
00253 }
00254 
00255 /* Given data, searches the table t for its first occurrence, and returns the 
00256 key related to it. */
00257 char *hash_key ( HashTable *t, void *data ) {
00258   int i;
00259 #ifdef CHAIN
00260   hashItem *h;
00261 #endif
00262 
00263   for ( i = 0; i < t->size; i++ ) {
00264 #ifdef CHAIN
00265     h = t->item[i];
00266     while ( h ) {
00267       if ( h->data == data )
00268         return h->key;
00269       h = h->next;
00270     }
00271 #else
00272     if ( t->item[i] && t->item[i]->data == data )
00273       return t->item[i]->key;
00274 #endif
00275   }
00276   return NULL;
00277 }

Generated at Thu Mar 1 10:05:32 2001 for GOCR API by doxygen1.2.2 written by Dimitri van Heesch, © 1997-2000