The Machine Perception Toolbox

[Introduction]- [News]- [Download]- [Screenshots]- [Manual (pdf)]- [Forums]- [API Reference]- [Repository ]

 

Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

hash.c

Go to the documentation of this file.
00001 /*
00002  * Copyright 1993, 1995 Christopher Seiwald.
00003  *
00004  * This file is part of Jam - see jam.c for Copyright information.
00005  */
00006 
00007 # include "jam.h"
00008 # include "hash.h"
00009 # include <assert.h>
00010 
00011 /* 
00012  * hash.c - simple in-memory hashing routines 
00013  *
00014  * External routines:
00015  *
00016  *     hashinit() - initialize a hash table, returning a handle
00017  *     hashitem() - find a record in the table, and optionally enter a new one
00018  *     hashdone() - free a hash table, given its handle
00019  *
00020  * Internal routines:
00021  *
00022  *     hashrehash() - resize and rebuild hp->tab, the hash table
00023  *
00024  * 4/29/93 - ensure ITEM's are aligned
00025  */
00026 
00027 char    *hashsccssid="@(#)hash.c        1.14  ()  6/20/88";
00028 
00029 /* Header attached to all data items entered into a hash table. */
00030 
00031 struct hashhdr {
00032         struct item *next;
00033         unsigned int keyval;                    /* for quick comparisons */
00034 } ;
00035 
00036 /* This structure overlays the one handed to hashenter(). */
00037 /* It's actual size is given to hashinit(). */
00038 
00039 struct hashdata {
00040         char    *key;
00041         /* rest of user data */
00042 } ;
00043 
00044 typedef struct item {
00045         struct hashhdr hdr;
00046         struct hashdata data;
00047 } ITEM ;
00048 
00049 # define MAX_LISTS 32
00050 
00051 struct hash 
00052 {
00053         /*
00054          * the hash table, just an array of item pointers
00055          */
00056         struct {
00057                 int nel;
00058                 ITEM **base;
00059         } tab;
00060 
00061         int bloat;      /* tab.nel / items.nel */
00062         int inel;       /* initial number of elements */
00063 
00064         /*
00065          * the array of records, maintained by these routines
00066          * essentially a microallocator
00067          */ 
00068         struct {
00069                 int more;       /* how many more ITEMs fit in lists[ list ] */
00070         ITEM *free; /* free list of items */
00071                 char *next;     /* where to put more ITEMs in lists[ list ] */
00072                 int datalen;    /* length of records in this hash table */
00073                 int size;       /* sizeof( ITEM ) + aligned datalen */
00074                 int nel;        /* total ITEMs held by all lists[] */
00075                 int list;       /* index into lists[] */
00076 
00077                 struct {
00078                         int nel;        /* total ITEMs held by this list */
00079                         char *base;     /* base of ITEMs array */
00080                 } lists[ MAX_LISTS ];
00081         } items;
00082 
00083         char *name;     /* just for hashstats() */
00084 } ;
00085 
00086 static void hashrehash( struct hash *hp );
00087 static void hashstat( struct hash *hp );
00088 
00089 /*
00090  * hash_free() - remove the given item from the table if it's there.
00091  * Returns 1 if found, 0 otherwise.
00092  *
00093  * NOTE: 2nd argument is HASHDATA*, not HASHDATA** as elsewhere.
00094  */
00095 int
00096 hash_free(
00097         register struct hash *hp,
00098         HASHDATA *data)
00099 {
00100         ITEM **prev;
00101         register ITEM **i;
00102         unsigned char *b = (unsigned char*)data->key;
00103         unsigned int keyval;
00104 
00105         keyval = *b;
00106 
00107         while( *b )
00108                 keyval = keyval * 2147059363 + *b++;
00109 
00110     prev = hp->tab.base + ( keyval % hp->tab.nel );
00111         while(*prev )
00112     {
00113         register ITEM* i = *prev;
00114             if( keyval == i->hdr.keyval && 
00115             !strcmp( i->data.key, data->key ) )
00116         {
00117             /* unlink the record from the hash chain */
00118             *prev = i->hdr.next;
00119             /* link it into the freelist */
00120             i->hdr.next = hp->items.free;
00121             hp->items.free = i;
00122             /* mark it free so we skip it during enumeration */
00123             i->data.key = 0;
00124             /* we have another item */
00125             hp->items.more++;
00126             return 1;
00127         }
00128         prev = &i->hdr.next;
00129     }
00130     return 0;
00131 }
00132 
00133 /*
00134  * hashitem() - find a record in the table, and optionally enter a new one
00135  */
00136 
00137 int
00138 hashitem(
00139         register struct hash *hp,
00140         HASHDATA **data,
00141         int enter )
00142 {
00143         ITEM **base;
00144         register ITEM *i;
00145         unsigned char *b = (unsigned char*)(*data)->key;
00146         unsigned int keyval;
00147 
00148         if( enter && !hp->items.more )
00149             hashrehash( hp );
00150 
00151         if( !enter && !hp->items.nel )
00152             return 0;
00153 
00154         keyval = *b;
00155 
00156         while( *b )
00157                 keyval = keyval * 2147059363 + *b++;
00158 
00159         base = hp->tab.base + ( keyval % hp->tab.nel );
00160 
00161         for( i = *base; i; i = i->hdr.next )
00162             if( keyval == i->hdr.keyval && 
00163                 !strcmp( i->data.key, (*data)->key ) )
00164         {
00165                 *data = &i->data;
00166                 return !0;
00167         }
00168 
00169         if( enter ) 
00170         {
00171         /* try to grab one from the free list */
00172         if ( hp->items.free )
00173         {
00174             i = hp->items.free;
00175             hp->items.free = i->hdr.next;
00176             assert( i->data.key == 0 );
00177         }
00178         else
00179         {
00180             i = (ITEM *)hp->items.next;
00181             hp->items.next += hp->items.size;
00182         }
00183                 hp->items.more--;
00184                 memcpy( (char *)&i->data, (char *)*data, hp->items.datalen );
00185                 i->hdr.keyval = keyval;
00186                 i->hdr.next = *base;
00187                 *base = i;
00188                 *data = &i->data;
00189         }
00190 
00191         return 0;
00192 }
00193 
00194 /*
00195  * hashrehash() - resize and rebuild hp->tab, the hash table
00196  */
00197 
00198 static void hashrehash( register struct hash *hp )
00199 {
00200         int i = ++hp->items.list;
00201 
00202         hp->items.more = i ? 2 * hp->items.nel : hp->inel;
00203         hp->items.next = (char *)malloc( hp->items.more * hp->items.size );
00204     hp->items.free = 0;
00205     
00206         hp->items.lists[i].nel = hp->items.more;
00207         hp->items.lists[i].base = hp->items.next;
00208         hp->items.nel += hp->items.more;
00209 
00210         if( hp->tab.base )
00211                 free( (char *)hp->tab.base );
00212 
00213         hp->tab.nel = hp->items.nel * hp->bloat;
00214         hp->tab.base = (ITEM **)malloc( hp->tab.nel * sizeof(ITEM **) );
00215 
00216         memset( (char *)hp->tab.base, '\0', hp->tab.nel * sizeof( ITEM * ) );
00217 
00218         for( i = 0; i < hp->items.list; i++ )
00219         {
00220                 int nel = hp->items.lists[i].nel;
00221                 char *next = hp->items.lists[i].base;
00222 
00223                 for( ; nel--; next += hp->items.size )
00224                 {
00225                         register ITEM *i = (ITEM *)next;
00226                         ITEM **ip = hp->tab.base + i->hdr.keyval % hp->tab.nel;
00227             /* code currently assumes rehashing only when there are no free items */
00228             assert( i->data.key != 0 ); 
00229             
00230                         i->hdr.next = *ip;
00231                         *ip = i;
00232                 }
00233         }
00234 }
00235 
00236 void hashenumerate( struct hash *hp, void (*f)(void*,void*), void* data )
00237 {
00238     int i;
00239     for( i = 0; i <= hp->items.list; i++ )
00240     {
00241         char *next = hp->items.lists[i].base;
00242         int nel = hp->items.lists[i].nel;
00243         if ( i == hp->items.list )
00244             nel -= hp->items.more;
00245 
00246         for( ; nel--; next += hp->items.size )
00247         {
00248             register ITEM *i = (ITEM *)next;
00249             
00250             if ( i->data.key != 0 ) /* don't enumerate freed items */
00251                 f(&i->data, data);
00252         }
00253     }
00254 }
00255 
00256 /* --- */
00257 
00258 # define ALIGNED(x) ( ( x + sizeof( ITEM ) - 1 ) & ~( sizeof( ITEM ) - 1 ) )
00259 
00260 /*
00261  * hashinit() - initialize a hash table, returning a handle
00262  */
00263 
00264 struct hash *
00265 hashinit( 
00266         int datalen,
00267         char *name )
00268 {
00269         struct hash *hp = (struct hash *)malloc( sizeof( *hp ) );
00270 
00271         hp->bloat = 3;
00272         hp->tab.nel = 0;
00273         hp->tab.base = (ITEM **)0;
00274         hp->items.more = 0;
00275     hp->items.free = 0;
00276         hp->items.datalen = datalen;
00277         hp->items.size = sizeof( struct hashhdr ) + ALIGNED( datalen );
00278         hp->items.list = -1;
00279         hp->items.nel = 0;
00280         hp->inel = 11;
00281         hp->name = name;
00282 
00283         return hp;
00284 }
00285 
00286 /*
00287  * hashdone() - free a hash table, given its handle
00288  */
00289 
00290 void
00291 hashdone( struct hash *hp )
00292 {
00293         int i;
00294 
00295         if( !hp )
00296             return;
00297 
00298         if( DEBUG_MEM )
00299             hashstat( hp );
00300 
00301         if( hp->tab.base )
00302                 free( (char *)hp->tab.base );
00303         for( i = 0; i <= hp->items.list; i++ )
00304                 free( hp->items.lists[i].base );
00305         free( (char *)hp );
00306 }
00307 
00308 /* ---- */
00309 
00310 static void
00311 hashstat( struct hash *hp )
00312 {
00313         ITEM **tab = hp->tab.base;
00314         int nel = hp->tab.nel;
00315         int count = 0;
00316         int sets = 0;
00317         int run = ( tab[ nel - 1 ] != (ITEM *)0 );
00318         int i, here;
00319 
00320         for( i = nel; i > 0; i-- )
00321         {
00322                 if( here = ( *tab++ != (ITEM *)0 ) )
00323                         count++;
00324                 if( here && !run )
00325                         sets++;
00326                 run = here;
00327         }
00328 
00329         printf( "%s table: %d+%d+%d (%dK+%dK) items+table+hash, %f density\n",
00330                 hp->name, 
00331                 count, 
00332                 hp->items.nel,
00333                 hp->tab.nel,
00334                 hp->items.nel * hp->items.size / 1024,
00335                 hp->tab.nel * sizeof( ITEM ** ) / 1024,
00336                 (float)count / (float)sets );
00337 }

Generated on Mon Nov 8 17:07:35 2004 for MPT by  doxygen 1.3.9.1