Initial check in. Preliminary development stage.

From-SVN: r46
This commit is contained in:
Dennis Glatting 1991-10-24 00:45:39 +00:00
parent e545f2b026
commit 4217c4568b
2 changed files with 371 additions and 0 deletions

237
gcc/objc/hash.c Normal file
View File

@ -0,0 +1,237 @@
/* -*-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;
}

134
gcc/objc/hash.h Normal file
View File

@ -0,0 +1,134 @@
/* -*-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