swig/SWIG/Source/DOH/Doh/hash.c
Dave Beazley 784ddea377 Fixed file/line attributes
git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@94 626c5289-ae23-0410-ae9c-e8d60b6d4f22
2000-01-14 03:48:02 +00:00

571 lines
13 KiB
C

/****************************************************************************
* DOH
*
* Author : David Beazley
*
* Department of Computer Science
* University of Chicago
* 1100 E 58th Street
* Chicago, IL 60637
* beazley@cs.uchicago.edu
*
* Please read the file LICENSE for the copyright and terms by which DOH
* can be used and distributed.
****************************************************************************/
#include "dohint.h"
/***********************************************************************
* $Header$
*
* hash.c
*
* Hash table implementation.
***********************************************************************/
/* Hash node */
typedef struct HashNode {
DOH *key;
DOH *object;
struct HashNode *next;
} HashNode;
/* Hash object */
typedef struct Hash {
DOHXCOMMON;
HashNode **hashtable;
int hashsize;
int currentindex;
int nitems;
HashNode *current;
} Hash;
/* -----------------------------------------------------------------------------
Key interning. This is used for getattr,setattr functions.
The following structure maps raw char * entries to string objects.
----------------------------------------------------------------------------- */
typedef struct KeyValue {
char *cstr;
DOH *sstr;
struct KeyValue *left;
struct KeyValue *right;
} KeyValue;
static KeyValue *root = 0;
static DOH *find_key(char *c) {
KeyValue *r, *s;
int d = 0;
r = root;
s = 0;
while (r) {
s = r;
d = strcmp(r->cstr,c);
if (d == 0) return r->sstr;
if (d < 0) r = r->left;
else r = r->right;
}
/* fprintf(stderr,"Interning '%s'\n", c); */
r = (KeyValue *) DohMalloc(sizeof(KeyValue));
r->cstr = (char *) DohMalloc(strlen(c)+1);
strcpy(r->cstr,c);
r->sstr = NewString(c);
DohIntern(r->sstr);
r->left = 0;
r->right = 0;
if (!s) { root = r; }
else {
if (d < 0) s->left = r;
else s->right = r;
}
return r->sstr;
}
/* Forward references */
DOH *CopyHash(DOH *h);
void DelHash(DOH *h);
void Hash_clear(DOH *);
void Hash_scope(DOH *, int);
int Hash_setattr(DOH *, DOH *k, DOH *obj);
DOH *Hash_getattr(DOH *h, DOH *k);
int Hash_delattr(DOH *h, DOH *k);
DOH *Hash_firstkey(DOH *h);
DOH *Hash_nextkey(DOH *h);
DOH *Hash_str(DOH *h);
int Hash_len(DOH *h);
#define HASH_INIT_SIZE 7
static HashNode *NewNode(DOH *k, void *obj)
{
HashNode *hn = (HashNode *) DohMalloc(sizeof(HashNode));
hn->key = k;
Incref(hn->key);
hn->object = obj;
Incref(obj);
hn->next = 0;
return hn;
}
static void DelNode(HashNode *hn)
{
Delete(hn->key);
Delete(hn->object);
DohFree(hn);
}
static DohMappingMethods HashMappingMethods = {
Hash_getattr,
Hash_setattr,
Hash_delattr,
Hash_firstkey,
Hash_nextkey,
};
static DohPositionalMethods HashPositionalMethods = {
XBase_setfile,
XBase_getfile,
XBase_setline,
XBase_getline
};
static DohObjInfo HashType = {
"Hash", /* objname */
sizeof(Hash), /* size */
DelHash, /* doh_del */
CopyHash, /* doh_copy */
Hash_clear, /* doh_clear */
Hash_scope, /* doh_scope */
Hash_str, /* doh_str */
0, /* doh_data */
0, /* doh_dump */
0, /* doh_load */
Hash_len, /* doh_len */
0, /* doh_hash */
0, /* doh_cmp */
&HashMappingMethods, /* doh_mapping */
0, /* doh_sequence */
0, /* doh_file */
0, /* doh_string */
0, /* doh_callable */
&HashPositionalMethods, /* doh_positional */
};
DohObjInfo *Hash_type() {
return &HashType;
}
int Hash_check(DOH *so) {
Hash *h = (Hash *) so;
if (!h) return 0;
if (!DohCheck(so)) return 0;
if (h->objinfo != &HashType) return 0;
return 1;
}
/* -----------------------------------------------------------------------------
* NewHash() - Create a new hash table
* ----------------------------------------------------------------------------- */
DOH *NewHash() {
Hash *h;
int i;
h = (Hash *) DohObjMalloc(sizeof(Hash));
DohXInit(h);
h->hashsize = HASH_INIT_SIZE;
h->hashtable = (HashNode **) DohMalloc(h->hashsize*sizeof(HashNode *));
for (i = 0; i < h->hashsize; i++) {
h->hashtable[i] = 0;
}
h->currentindex = -1;
h->current = 0;
h->nitems = 0;
h->objinfo = &HashType;
return (DOH *) h;
}
/* -----------------------------------------------------------------------------
* DOH *CopyHash(DOH *ho) - Copy a hash table
* ----------------------------------------------------------------------------- */
DOH *CopyHash(DOH *ho) {
Hash *h, *nh;
HashNode *n;
int i;
h = (Hash *) ho;
nh = (Hash *) DohObjMalloc(sizeof(Hash));
DohXInit(h);
nh->hashsize = h->hashsize;
nh->hashtable = (HashNode **) DohMalloc(nh->hashsize*sizeof(HashNode *));
for (i = 0; i < nh->hashsize; i++) {
nh->hashtable[i] = 0;
}
nh->currentindex = -1;
nh->current = 0;
nh->nitems = 0;
nh->objinfo = h->objinfo;
nh->line = h->line;
nh->file = h->file;
if (nh->file) Incref(nh->file);
for (i = 0; i < h->hashsize; i++) {
if ((n = h->hashtable[i])) {
while (n) {
Hash_setattr(nh, n->key, n->object);
n = n->next;
}
}
}
return (DOH *) nh;
}
/* -----------------------------------------------------------------------------
* DelHash() - Delete a hash table
* ----------------------------------------------------------------------------- */
void DelHash(DOH *ho)
{
Hash *h;
HashNode *n,*next;
int i;
h = (Hash *) ho;
for (i = 0; i < h->hashsize; i++) {
if ((n = h->hashtable[i])) {
while (n) {
next = n->next;
DelNode(n);
n = next;
}
}
}
DohFree(h->hashtable);
h->hashtable = 0;
h->hashsize = 0;
Delete(h->file);
DohObjFree(h);
}
/* -----------------------------------------------------------------------------
* Hash_clear(DOH *ho) - Clear all entries in a hash table
* ----------------------------------------------------------------------------- */
void Hash_clear(DOH *ho)
{
Hash *h;
HashNode *n,*next;
int i;
h = (Hash *) ho;
for (i = 0; i < h->hashsize; i++) {
if ((n = h->hashtable[i])) {
while (n) {
next = n->next;
DelNode(n);
n = next;
}
}
h->hashtable[i] = 0;
}
h->nitems = 0;
}
/* -----------------------------------------------------------------------------
* Hash_scope(DOH *ho, int s) - Clear all entries in a hash table
* ----------------------------------------------------------------------------- */
void Hash_scope(DOH *ho, int s)
{
Hash *h;
HashNode *n;
int i;
h = (Hash *) ho;
if (h->flags & DOH_FLAG_SETSCOPE) return;
if (s < h->scope) h->scope = s;
h->flags = h->flags | DOH_FLAG_SETSCOPE;
for (i = 0; i < h->hashsize; i++) {
if ((n = h->hashtable[i])) {
while (n) {
Setscope(n->object,s);
Setscope(n->key,s);
n = n->next;
}
}
}
h->flags = h->flags & ~DOH_FLAG_SETSCOPE;
}
/* -----------------------------------------------------------------------------
* static resize(Hash *h) - Resizes the hash table
* ----------------------------------------------------------------------------- */
static void resize(Hash *h) {
HashNode *n, *next, **table;
int oldsize, newsize;
int i, p, hv;
if (h->nitems < 2*h->hashsize) return;
/* Too big. We have to rescale everything now */
oldsize = h->hashsize;
/* Calculate a new size */
newsize = 2*oldsize+1;
p = 3;
while (p < (newsize >> 1)) {
if (((newsize/p)*p) == newsize) {
newsize+=2;
p = 3;
continue;
}
p = p + 2;
}
table = (HashNode **) DohMalloc(newsize*sizeof(HashNode *));
for (i = 0; i < newsize; i++ ) {
table[i] = 0;
}
/* Walk down the old set of nodes */
h->hashsize = newsize;
for (i = 0; i < oldsize; i++) {
n = h->hashtable[i];
while (n) {
hv = Hashval(n->key) % newsize;
next = n->next;
n->next = table[hv];
table[hv] = n;
n = next;
}
}
DohFree(h->hashtable);
h->hashtable = table;
}
/* -----------------------------------------------------------------------------
* int Hash_setattr(DOH *h, DOH *k, DOH *obj) - Adds an object to a hash
* ----------------------------------------------------------------------------- */
int
Hash_setattr(DOH *ho, DOH *k, DOH *obj) {
int hv;
HashNode *n, *prev;
Hash *h;
if (!DohCheck(k)) k = find_key(k);
if (!DohCheck(obj)) {
obj = NewString((char *) obj);
}
h = (Hash *) ho;
hv = (Hashval(k)) % h->hashsize;
n = h->hashtable[hv];
prev = 0;
while (n) {
if (Cmp(n->key,k) == 0) {
HashNode *nn;
if (prev) {
prev->next = n->next;
h->hashtable[hv] = n->next;
} else {
h->hashtable[hv] = n->next;
}
nn = n->next;
DelNode(n);
h->nitems--;
n = nn;
} else {
prev = n;
n = n->next;
}
}
/* Add this to the table */
n = NewNode(k,obj);
Setscope(n->key,h->scope);
Setscope(n->object,h->scope);
if (prev) prev->next = n;
else h->hashtable[hv] = n;
h->nitems++;
resize(h);
return 0;
}
/* -----------------------------------------------------------------------------
* DOH *Hash_getattr(DOH *ho, DOH *k) - Get an item from the hash table
* ----------------------------------------------------------------------------- */
DOH *
Hash_getattr(DOH *ho, DOH *k) {
int hv;
HashNode *n;
Hash *h;
if (!DohCheck(k)) k = find_key(k);
h = (Hash *) ho;
hv = Hashval(k) % h->hashsize;
n = h->hashtable[hv];
while (n) {
if (Cmp(n->key, k) == 0) return n->object;
n = n->next;
}
return 0;
}
/* -----------------------------------------------------------------------------
* void Hash_delattr(DOH *ho, DOH *k) - Delete an element from the table
* ----------------------------------------------------------------------------- */
int
Hash_delattr(DOH *ho, DOH *k)
{
HashNode *n, *prev;
int hv;
Hash *h;
if (!DohCheck(k)) k = find_key(k);
h = (Hash *) ho;
hv = Hashval(k) % h->hashsize;
n = h->hashtable[hv];
prev = 0;
while (n) {
if (Cmp(n->key, k) == 0) {
/* Found it, kill it */
if (prev) {
prev->next = n->next;
} else {
h->hashtable[hv] = n->next;
}
DelNode(n);
h->nitems--;
return 1;
}
prev = n;
n = n->next;
}
return 0;
}
/* -----------------------------------------------------------------------------
* Iterators
* ----------------------------------------------------------------------------- */
static HashNode *hash_first(DOH *ho) {
Hash *h = (Hash *) ho;
h->currentindex = 0;
h->current = 0;
while (!h->hashtable[h->currentindex] && (h->currentindex < h->hashsize))
h->currentindex++;
if (h->currentindex >= h->hashsize) return 0;
h->current = h->hashtable[h->currentindex];
return h->current;
}
static HashNode *hash_next(DOH *ho) {
Hash *h = (Hash *) ho;
if (h->currentindex < 0) return hash_first(h);
/* Try to move to the next entry */
h->current = h->current->next;
if (h->current) {
return h->current;
}
h->currentindex++;
while ((h->currentindex < h->hashsize) && !h->hashtable[h->currentindex])
h->currentindex++;
if (h->currentindex >= h->hashsize) return 0;
h->current = h->hashtable[h->currentindex];
return h->current;
}
DOH *
Hash_first(DOH *ho) {
HashNode *hn = hash_first(ho);
if (hn) return hn->object;
return 0;
}
DOH *
Hash_next(DOH *ho)
{
HashNode *hn = hash_next(ho);
if (hn) return hn->object;
return 0;
}
DOH *
Hash_firstkey(DOH *ho)
{
HashNode *hn = hash_first(ho);
if (hn) return hn->key;
return 0;
}
DOH *
Hash_nextkey(DOH *ho)
{
HashNode *hn = hash_next(ho);
if (hn) return hn->key;
return 0;
}
/* -----------------------------------------------------------------------------
* String *Hash_str(DOH *ho) - Create a string representation of a hash
* ----------------------------------------------------------------------------- */
DOH *
Hash_str(DOH *ho) {
int i;
HashNode *n;
DOH *s;
Hash *h;
h = (Hash *) ho;
s = NewString("");
if (h->flags & DOH_FLAG_PRINT) {
Printf(s,"Hash(0x%x)",h);
return s;
}
h->flags = h->flags | DOH_FLAG_PRINT;
Printf(s,"Hash {\n");
for (i = 0; i < h->hashsize; i++) {
n = h->hashtable[i];
while (n) {
Printf(s," '%s' : %s, \n", n->key, n->object);
n = n->next;
}
}
Printf(s,"}\n");
h->flags = h->flags & ~DOH_FLAG_PRINT;
return s;
}
/* -----------------------------------------------------------------------------
* Hash_len(DOH *)
* ----------------------------------------------------------------------------- */
int Hash_len(DOH *ho) {
Hash *h = (Hash *) ho;
return h->nitems;
}
/* -----------------------------------------------------------------------------
* Hash_keys(DOH *)
*
* Return a list of keys
* ----------------------------------------------------------------------------- */
DOH *Hash_keys(DOH *so) {
DOH *keys;
DOH *k;
keys = NewList();
k = Firstkey(so);
while (k) {
Append(keys,k);
k = Nextkey(so);
}
/* List_sort(keys); */
return keys;
}