Initial import of the CDE 2.1.30 sources from the Open Group.
This commit is contained in:
218
cde/lib/csa/hash.c
Normal file
218
cde/lib/csa/hash.c
Normal file
@@ -0,0 +1,218 @@
|
||||
/* $XConsortium: hash.c /main/1 1996/04/21 19:23:21 drk $ */
|
||||
/*
|
||||
* (c) Copyright 1993, 1994 Hewlett-Packard Company
|
||||
* (c) Copyright 1993, 1994 International Business Machines Corp.
|
||||
* (c) Copyright 1993, 1994 Novell, Inc.
|
||||
* (c) Copyright 1993, 1994 Sun Microsystems, Inc.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Synopsis:
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
void * _DtCmMakeHash(int size)
|
||||
|
||||
void * _DtCmMakeIHash(int size)
|
||||
|
||||
void ** _DtCmGetHash(void * tbl, unsigned char * key)
|
||||
|
||||
void ** _DtCmFindHash(void * tbl,unsigned char * key)
|
||||
|
||||
void ** _DtCmDelHash(void * tbl, unsigned char * key)
|
||||
|
||||
int _DtCmOperateHash(void * tbl, void (*op_func)(), void * usr_arg)
|
||||
|
||||
void _DtCmDestroyHash(void * tbl, int (*des_func)(), void * usr_arg)
|
||||
|
||||
|
||||
Description:
|
||||
|
||||
These routines provide a general purpose hash table facility that
|
||||
supports multiple open hash tables. Each entry in the table consists of a
|
||||
key and a data ptr. The key is a null terminated character string, while
|
||||
the data ptr is opaque. Since all the entries are maintained in a doubly
|
||||
linked lists, deletions and operations on entire table execute very quickly.
|
||||
This make these routines suitable for use when the tables may be very ephemeral.
|
||||
|
||||
_DtCmMakeHash returns a pointer to the created table. The size argument
|
||||
indicate the number of buckets the routine is to allocate. This should be ~
|
||||
the max number of items expected in the table for maximum performance....
|
||||
but /2 or /3 should still be ok. Note that for maximum efficiency the hash
|
||||
table size should be a prime number (a side effect of the hash alorithm).
|
||||
|
||||
_DtCmMakeIHash performs the same function as _DtCmMakeHash, except that the hash
|
||||
routines will use the key arguments as arbitrary integers rather than strings.
|
||||
|
||||
_DtCmGetHash searches the specified hash table tbl for an entry with the
|
||||
specified key. If the entry does not exist, it is created with a NULL data
|
||||
ptr. The routine returns a ptr to the area where the data ptr is (can be)
|
||||
stored.
|
||||
|
||||
_DtCmFindHash searchs the table for an entry with the specified key. If the
|
||||
entry is found, the address of the data pointer associated with the key is
|
||||
returned. If no such entry exists, the routine returns NULL.
|
||||
|
||||
_DtCmDelHash deletes the specified table entry and returns the associated data
|
||||
ptr. If the entry did not exist ( or the data ptr was NULL), the routine
|
||||
returns NULL.
|
||||
|
||||
_DtCmOperateHash calls the routine pointed to by op_func once for each entry
|
||||
in tbl, with three arguments: the data ptr, the usr_arg ptr and a ptr to the
|
||||
key for that entry (which should NOT be altered). This is useful for
|
||||
transversing a hash table quickly and operating on the entries. Note that
|
||||
the order of the traversal of the hash table is the reverse order of
|
||||
insertion.
|
||||
|
||||
_DtCmDestroyHash destroys the specified hash table after operating on it
|
||||
with the specified des_func function as described for _DtCmOperateHash. All storage
|
||||
allocated by the hash routines is reclaimed.
|
||||
|
||||
Author: Bart Smaalders 1/89
|
||||
|
||||
|
||||
*/
|
||||
#include <EUSCompat.h>
|
||||
#include <stdio.h> /* grab NULL define */
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "hash.h"
|
||||
|
||||
static int hash_string();
|
||||
|
||||
typedef struct hash_entry {
|
||||
struct hash_entry
|
||||
* next_entry,
|
||||
* right_entry,
|
||||
* left_entry;
|
||||
unsigned char * key;
|
||||
void * data;
|
||||
} hash_entry;
|
||||
|
||||
typedef struct hash {
|
||||
int size;
|
||||
hash_entry ** table;
|
||||
hash_entry * start;
|
||||
enum hash_type { String_Key = 0 , Integer_Key = 1} hash_type;
|
||||
} hash;
|
||||
|
||||
|
||||
void * _DtCmMakeHash(int size)
|
||||
{
|
||||
hash * ptr;
|
||||
|
||||
ptr = (hash *) malloc(sizeof(*ptr));
|
||||
ptr->size = size;
|
||||
ptr->table = (hash_entry **) malloc( (unsigned) (sizeof(hash_entry *) * size) );
|
||||
(void)memset((char *) ptr->table, (char) 0, sizeof(hash_entry *)*size);
|
||||
ptr->start = NULL;
|
||||
ptr->hash_type = String_Key;
|
||||
return((void*)ptr);
|
||||
}
|
||||
|
||||
void ** _DtCmGetHash(void * t, const unsigned char * key)
|
||||
{
|
||||
hash * tbl = (hash *) t;
|
||||
register int bucket;
|
||||
register hash_entry * tmp;
|
||||
hash_entry * new;
|
||||
|
||||
if(tbl->hash_type == String_Key)
|
||||
tmp = tbl->table[bucket = hash_string(key, tbl->size)];
|
||||
else
|
||||
tmp = tbl->table[bucket = abs((long)key) % tbl->size];
|
||||
|
||||
if(tbl->hash_type == String_Key)
|
||||
while(tmp!=NULL)
|
||||
{
|
||||
if(strcmp((char *)tmp->key, (char *)key)==0)
|
||||
return(&tmp->data);
|
||||
tmp = tmp->next_entry;
|
||||
}
|
||||
else
|
||||
while(tmp!=NULL)
|
||||
{
|
||||
if(tmp->key == key)
|
||||
return(&tmp->data);
|
||||
tmp = tmp->next_entry;
|
||||
}
|
||||
|
||||
/*
|
||||
not found....
|
||||
insert new entry into bucket...
|
||||
*/
|
||||
|
||||
new = (hash_entry *) malloc(sizeof(*new));
|
||||
new->key = (unsigned char *)((tbl->hash_type == String_Key)?(unsigned char *)strdup((char *)key):key);
|
||||
/*
|
||||
hook into chain from tbl...
|
||||
*/
|
||||
new->right_entry = NULL;
|
||||
new->left_entry = tbl->start;
|
||||
tbl->start = new;
|
||||
/*
|
||||
hook into bucket chain
|
||||
*/
|
||||
new->next_entry = tbl->table[bucket];
|
||||
tbl->table[bucket] = new;
|
||||
new->data = NULL; /* so we know that it is new */
|
||||
return((void*)& new->data);
|
||||
}
|
||||
|
||||
void ** _DtCmFindHash(void * t, const unsigned char * key)
|
||||
{
|
||||
register hash * tbl = (hash *) t;
|
||||
register hash_entry * tmp;
|
||||
|
||||
if(tbl->hash_type == String_Key)
|
||||
{
|
||||
tmp = tbl->table[hash_string(key, tbl->size)];
|
||||
for(;tmp!=NULL; tmp = tmp->next_entry)
|
||||
if(!strcmp((char *)tmp->key, (char *)key))
|
||||
return((void *)&tmp->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp = tbl->table[abs((long)key) % tbl->size];
|
||||
for(;tmp!=NULL; tmp = tmp->next_entry)
|
||||
if(tmp->key == key)
|
||||
return((void *)&tmp->data);
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
void _DtCmDestroyHash(void * t, int (*ptr)(), void * usr_arg)
|
||||
{
|
||||
hash * tbl = (hash *) t;
|
||||
register hash_entry * tmp = tbl->start, * prev;
|
||||
|
||||
while(tmp)
|
||||
{
|
||||
if(ptr)
|
||||
(*ptr)(tmp->data,usr_arg, tmp->key);
|
||||
|
||||
if(tbl->hash_type == String_Key)
|
||||
free(tmp->key);
|
||||
prev = tmp;
|
||||
tmp = tmp->left_entry;
|
||||
free((char *)prev);
|
||||
}
|
||||
free((char *)tbl->table);
|
||||
free(tbl);
|
||||
}
|
||||
|
||||
static int hash_string(s,modulo)
|
||||
register char *s;
|
||||
int modulo;
|
||||
{
|
||||
register unsigned result = 0;
|
||||
register int i=1;
|
||||
|
||||
while(*s!=0)
|
||||
result += (*s++ << i++);
|
||||
|
||||
return(result % modulo);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user