2005-03-01 15:36:23 +00:00
|
|
|
#include "hash.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2005-03-28 00:11:59 +00:00
|
|
|
#ifndef _WIN32
|
|
|
|
#ifndef stricmp
|
|
|
|
#define stricmp strcasecmp
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
2008-05-14 18:06:58 +00:00
|
|
|
// hash init assumes we get clean memory
|
2004-08-23 01:38:21 +00:00
|
|
|
void Hash_InitTable(hashtable_t *table, int numbucks, void *mem)
|
|
|
|
{
|
|
|
|
table->numbuckets = numbucks;
|
|
|
|
table->bucket = (bucket_t **)mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Hash_Key(char *name, int modulus)
|
|
|
|
{ //fixme: optimize.
|
|
|
|
unsigned int key;
|
|
|
|
for (key=0;*name; name++)
|
|
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
|
|
|
|
|
|
return (int)(key%modulus);
|
|
|
|
}
|
2004-12-05 16:32:44 +00:00
|
|
|
int Hash_KeyInsensative(char *name, int modulus)
|
|
|
|
{ //fixme: optimize.
|
|
|
|
unsigned int key;
|
|
|
|
for (key=0;*name; name++)
|
|
|
|
{
|
|
|
|
if (*name >= 'A' && *name <= 'Z')
|
|
|
|
key += ((key<<3) + (key>>28) + (*name-'A'+'a'));
|
|
|
|
else
|
|
|
|
key += ((key<<3) + (key>>28) + *name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (int)(key%modulus);
|
|
|
|
}
|
2004-08-23 01:38:21 +00:00
|
|
|
|
|
|
|
void *Hash_Get(hashtable_t *table, char *name)
|
|
|
|
{
|
|
|
|
int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-12-05 16:32:44 +00:00
|
|
|
void *Hash_GetInsensative(hashtable_t *table, char *name)
|
|
|
|
{
|
2005-02-09 19:32:30 +00:00
|
|
|
int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
2004-12-05 16:32:44 +00:00
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!stricmp(name, buck->key.string))
|
2004-12-05 16:32:44 +00:00
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2004-08-23 01:38:21 +00:00
|
|
|
void *Hash_GetKey(hashtable_t *table, int key)
|
|
|
|
{
|
|
|
|
int bucknum = key%table->numbuckets;
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (buck->key.value == key)
|
2004-08-23 01:38:21 +00:00
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
void *Hash_GetNext(hashtable_t *table, char *name, void *old)
|
|
|
|
{
|
|
|
|
int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
if (buck->data == old) //found the old one
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
if (!buck)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
buck = buck->next;//don't return old
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2005-02-09 19:32:30 +00:00
|
|
|
void *Hash_GetNextInsensative(hashtable_t *table, char *name, void *old)
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
2005-02-09 19:32:30 +00:00
|
|
|
int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
|
|
bucket_t *buck;
|
2004-08-23 01:38:21 +00:00
|
|
|
|
2005-02-09 19:32:30 +00:00
|
|
|
buck = table->bucket[bucknum];
|
2004-08-23 01:38:21 +00:00
|
|
|
|
2005-02-09 19:32:30 +00:00
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2005-02-09 19:32:30 +00:00
|
|
|
{
|
|
|
|
if (buck->data == old) //found the old one
|
|
|
|
break;
|
|
|
|
}
|
2004-08-23 01:38:21 +00:00
|
|
|
|
2005-02-09 19:32:30 +00:00
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
if (!buck)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
buck = buck->next;//don't return old
|
|
|
|
while(buck)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2005-02-09 19:32:30 +00:00
|
|
|
return buck->data;
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
2004-08-23 01:38:21 +00:00
|
|
|
}
|
2005-02-09 19:32:30 +00:00
|
|
|
|
|
|
|
|
|
|
|
void *Hash_Add(hashtable_t *table, char *name, void *data, bucket_t *buck)
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
|
|
|
|
buck->data = data;
|
2007-09-17 20:35:39 +00:00
|
|
|
buck->key.string = name;
|
2004-08-23 01:38:21 +00:00
|
|
|
buck->next = table->bucket[bucknum];
|
|
|
|
table->bucket[bucknum] = buck;
|
|
|
|
|
|
|
|
return buck;
|
|
|
|
}
|
2004-12-05 16:32:44 +00:00
|
|
|
void *Hash_AddInsensative(hashtable_t *table, char *name, void *data, bucket_t *buck)
|
|
|
|
{
|
|
|
|
int bucknum = Hash_KeyInsensative(name, table->numbuckets);
|
|
|
|
|
|
|
|
buck->data = data;
|
2007-09-17 20:35:39 +00:00
|
|
|
buck->key.string = name;
|
2004-12-05 16:32:44 +00:00
|
|
|
buck->next = table->bucket[bucknum];
|
|
|
|
table->bucket[bucknum] = buck;
|
|
|
|
|
|
|
|
return buck;
|
|
|
|
}
|
2005-03-01 15:36:23 +00:00
|
|
|
void *Hash_AddKey(hashtable_t *table, int key, void *data, bucket_t *buck)
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
int bucknum = key%table->numbuckets;
|
|
|
|
|
|
|
|
buck->data = data;
|
2007-09-17 20:35:39 +00:00
|
|
|
buck->key.value = key;
|
2004-08-23 01:38:21 +00:00
|
|
|
buck->next = table->bucket[bucknum];
|
|
|
|
table->bucket[bucknum] = buck;
|
|
|
|
|
|
|
|
return buck;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hash_Remove(hashtable_t *table, char *name)
|
|
|
|
{
|
|
|
|
int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(buck->next)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->next->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hash_RemoveData(hashtable_t *table, char *name, void *data)
|
|
|
|
{
|
|
|
|
int bucknum = Hash_Key(name, table->numbuckets);
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
|
|
|
if (buck->data == data)
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(buck->next)
|
|
|
|
{
|
|
|
|
if (buck->next->data == data)
|
2007-09-17 20:35:39 +00:00
|
|
|
if (!STRCMP(name, buck->next->key.string))
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Hash_RemoveKey(hashtable_t *table, int key)
|
|
|
|
{
|
|
|
|
int bucknum = key%table->numbuckets;
|
|
|
|
bucket_t *buck;
|
|
|
|
|
|
|
|
buck = table->bucket[bucknum];
|
|
|
|
|
2007-09-17 20:35:39 +00:00
|
|
|
if (buck->key.value == key)
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
table->bucket[bucknum] = buck->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
while(buck->next)
|
|
|
|
{
|
2007-09-17 20:35:39 +00:00
|
|
|
if (buck->next->key.value == key)
|
2004-08-23 01:38:21 +00:00
|
|
|
{
|
|
|
|
buck->next = buck->next->next;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buck = buck->next;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|