--- /dev/null
+/* -*-c-*-
+ * This file contains the hashing implementation.
+ *
+ $Header$
+ $Author$
+ $Date$
+ $Log$
+*/
+
+
+#include <hash.h>
+#include <ObjC.h>
+
+#include <assert.h>
+#include <libc.h>
+#include <math.h>
+
+
+ /* Local forward decl. */
+ u_int hashValue( Cache_t, void* );
+
+
+Cache_t hash_new( u_int numberOfBuckets ) {
+
+ Cache_t retCache;
+ int i;
+
+
+ assert( numberOfBuckets );
+
+ /* Allocate the cache
+ structure. calloc() insures
+ its initialization for
+ default values. */
+ retCache = calloc( 1, sizeof( Cache ));
+ assert( retCache );
+
+ /* Allocate the array of
+ buckets for the cache.
+ calloc() initializes all of
+ the pointers to NULL. */
+ retCache->theNodeTable = calloc( numberOfBuckets, sizeof( CacheNode_t ));
+ assert( retCache->theNodeTable );
+
+ retCache->numberOfBuckets = numberOfBuckets;
+
+ /* Calculate the number of
+ bits required to represent
+ the hash mask. */
+ retCache->numberOfMaskBits =
+ ceil( log( retCache->numberOfBuckets ) / log( 2 ));
+
+ /* Form a bit mask for the
+ hash. */
+ for( i = 0; i < retCache->numberOfMaskBits; ++i )
+ retCache->mask = ( retCache->mask << 1 ) | 0x01 ;
+
+ assert( retCache->numberOfMaskBits );
+ assert( retCache->mask );
+
+ return retCache;
+}
+
+
+void hash_delete( Cache_t theCache ) {
+
+ void* aNode;
+
+
+ /* Purge all key/value pairs
+ from the table. */
+ while( aNode = hash_next( theCache, NULL ))
+ hash_remove( theCache, aNode );
+
+ /* Release the array of nodes
+ and the cache itself. */
+ free( theCache->theNodeTable );
+ free( theCache );
+}
+
+
+void hash_add( Cache_t theCache, void* aKey, void* aValue ) {
+
+ u_int indx = hashValue( theCache, aKey );
+ CacheNode_t aCacheNode = calloc( 1, sizeof( CacheNode ));
+
+
+ assert( aCacheNode );
+
+ /* Initialize the new node. */
+ aCacheNode->theKey = aKey;
+ aCacheNode->theValue = aValue;
+ aCacheNode->nextNode = ( *theCache->theNodeTable )[ indx ];
+
+ /* Debugging.
+
+ Check the list for another
+ key. */
+#ifdef DEBUG
+ { CacheNode_t checkHashNode = ( *theCache->theNodeTable )[ indx ];
+
+ while( checkHashNode ) {
+
+ assert( checkHashNode->theKey != aKey );
+ checkHashNode = checkHashNode->nextNode;
+ }
+ }
+
+ /* Install the node as the
+ first element on the list. */
+ ( *theCache->theNodeTable )[ indx ] = aCacheNode;
+
+#endif
+}
+
+
+void hash_remove( Cache_t theCache, void* aKey ) {
+
+ u_int indx = hashValue( theCache, aKey );
+ CacheNode_t aCacheNode = ( *theCache->theNodeTable )[ indx ];
+
+
+ /* We assume there is an entry
+ in the table. Error if it
+ is not. */
+ assert( aCacheNode );
+
+ /* Special case. First element
+ is the key/value pair to be
+ removed. */
+ if( aCacheNode->theKey == aKey ) {
+ ( *theCache->theNodeTable )[ indx ] = aCacheNode->nextNode;
+ free( aCacheNode );
+ } else {
+ /* Otherwise, find the hash
+ entry. */
+ CacheNode_t prevHashNode = aCacheNode;
+ BOOL removed = NO;
+
+ do {
+
+ if( aCacheNode->theKey == aKey ) {
+ prevHashNode->nextNode = aCacheNode->nextNode, removed = YES;
+ free( aCacheNode );
+ } else
+ prevHashNode = aCacheNode, aCacheNode = aCacheNode->nextNode;
+ } while( !removed && aCacheNode );
+ assert( removed );
+ }
+}
+
+
+void* hash_value_for_key( Cache_t theCache, void* aKey ) {
+
+ u_int indx = hashValue( theCache, aKey );
+ CacheNode_t aCacheNode = ( *theCache->theNodeTable )[ indx ];
+ void* retVal = NULL;
+
+
+ if( aCacheNode ) {
+ BOOL found = NO;
+
+ do {
+ if( aCacheNode->theKey == aKey )
+ retVal = aCacheNode->theValue, found = YES;
+ else
+ aCacheNode = aCacheNode->nextNode;
+ } while( !found && aCacheNode );
+ }
+
+ return retVal;
+}
+
+
+CacheNode_t hash_next( Cache_t theCache, CacheNode_t aCacheNode ) {
+
+ CacheNode_t theCacheNode = aCacheNode;
+
+
+ /* If the scan is being started
+ then reset the last node
+ visitied pointer and bucket
+ index. */
+ if( !theCacheNode )
+ theCache->lastBucket = 0;
+
+ /* If there is a node visited
+ last then check for another
+ entry in the same bucket;
+ Otherwise step to the next
+ bucket. */
+ if( theCacheNode )
+ if( theCacheNode->nextNode )
+ /* There is a node which
+ follows the last node
+ returned. Step to that node
+ and retun it. */
+ return theCacheNode->nextNode;
+ else
+ ++theCache->lastBucket;
+
+ /* If the list isn't exhausted
+ then search the buckets for
+ other nodes. */
+ if( theCache->lastBucket < theCache->numberOfBuckets ) {
+ /* Scan the remainder of the
+ buckets looking for an entry
+ at the head of the list.
+ Return the first item
+ found. */
+ while( theCache->lastBucket < theCache->numberOfBuckets )
+ if(( *theCache->theNodeTable )[ theCache->lastBucket ])
+ return ( *theCache->theNodeTable )[ theCache->lastBucket ];
+ else
+ ++theCache->lastBucket;
+
+ /* No further nodes were found
+ in the hash table. */
+ return NULL;
+ } else
+ return NULL;
+}
+
+
+u_int hashValue( Cache_t theCache, void* aKey ) {
+
+ u_int hash = 0;
+ int i;
+
+
+ assert( theCache->numberOfMaskBits );
+ for( i = 0; i < ( sizeof( aKey ) * 8 ); i += theCache->numberOfMaskBits )
+ hash ^= (( u_int )aKey ) >> i ;
+
+ return ( hash & theCache->mask ) % theCache->numberOfBuckets;
+}
+
--- /dev/null
+/* -*-c-*-
+ * This is a general purpose hash object.
+ *
+ * The hash object used throughout the run-time
+ * is an integer hash. The key and data is of type
+ * void*. The hashing function converts the key to
+ * an integer and computes it hash value.
+ *
+ $Header$
+ $Author$
+ $Date$
+ $Log$
+*/
+
+
+#ifndef _hash_INCLUDE_GNU
+#define _hash_INCLUDE_GNU
+
+ /* If someone is using a c++
+ compiler then adjust the
+ types in the file back
+ to C. */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+
+/*
+ * This data structure is used to hold items
+ * stored in a hash table. Each node holds
+ * a key/value pair.
+ *
+ * Items in the cache are really of type void*.
+ */
+typedef struct cache_node {
+ struct cache_node* nextNode; /* Pointer to next entry on
+ the list. NULL indicates
+ end of list. */
+ void* theKey; /* Key used to locate the
+ value. Used to locate
+ value when more than one
+ key computes the same hash
+ value. */
+ void* theValue; /* Value stored for the
+ key. */
+} CacheNode, *CacheNode_t;
+
+
+/*
+ * This data structure is the cache.
+ *
+ * It must be passed to all of the hashing routines
+ * (except for new).
+ */
+typedef struct cache {
+ /*
+ * Variables used to implement the
+ * hash itself.
+ */
+ CacheNode_t (* theNodeTable )[]; /* Pointer to an array of
+ hash nodes. */
+ u_int numberOfBuckets, /* Number of buckets
+ allocated for the hash
+ table (number of array
+ entries allocated for
+ "theCache"). */
+ mask, /* Mask used when computing
+ a hash value. The number
+ of bits set in the mask
+ is contained in the next
+ member variable. */
+ numberOfMaskBits; /* Number of bits used for
+ the mask. Useful for
+ efficient hash value
+ calculation. */
+ /*
+ * Variables used to implement indexing
+ * through the hash table.
+ */
+ u_int lastBucket; /* Tracks which entry in the
+ array where the last value
+ was returned. */
+} Cache, *Cache_t;
+
+
+ /* Prototypes for hash
+ functions. */
+ /* Allocate and initialize
+ a hash table. Hash table
+ size taken as a parameter.
+ A value of 0 is not
+ allowed. */
+Cache_t hash_new( u_int numberOfBuckets );
+ /* Deallocate all of the
+ hash nodes and the cache
+ itself. */
+void hash_delete( Cache_t theCache );
+ /* Add the key/value pair
+ to the hash table. assert()
+ if the key is already in
+ the hash. */
+void hash_add( Cache_t theCache, void* aKey, void* aValue );
+ /* Remove the key/value pair
+ from the hash table.
+ assert() if the key isn't
+ in the table. */
+void hash_remove( Cache_t theCache, void* aKey );
+ /* Given key, return its
+ value. Return NULL if the
+ key/value pair isn't in
+ the hash. */
+void* hash_value_for_key( Cache_t theCache, void* aKey );
+ /* Used to index through the
+ hash table. Start with NULL
+ to get the first entry.
+
+ Successive calls pass the
+ value returned previously.
+ ** Don't modify the hash
+ during this operation ***
+
+ Cache nodes are returned
+ such that key or value can
+ ber extracted. */
+CacheNode_t hash_next( Cache_t theCache, CacheNode_t aCacheNode );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif