Files
wmaker/WINGs/hashtable.c
T

423 lines
8.1 KiB
C
Raw Normal View History

#include <config.h>
1998-09-29 22:36:29 +00:00
#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "WUtil.h"
#define INITIAL_CAPACITY 23
typedef struct HashItem {
2009-08-20 00:59:40 +02:00
const void *key;
const void *data;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
struct HashItem *next; /* collided item list */
1998-09-29 22:36:29 +00:00
} HashItem;
typedef struct W_HashTable {
2009-08-20 00:59:40 +02:00
WMHashTableCallbacks callbacks;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
unsigned itemCount;
unsigned size; /* table size */
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
HashItem **table;
1998-09-29 22:36:29 +00:00
} HashTable;
#define HASH(table, key) (((table)->callbacks.hash ? \
2004-10-12 21:28:27 +00:00
(*(table)->callbacks.hash)(key) : hashPtr(key)) % (table)->size)
1998-09-29 22:36:29 +00:00
#define DUPKEY(table, key) ((table)->callbacks.retainKey ? \
2004-10-12 21:28:27 +00:00
(*(table)->callbacks.retainKey)(key) : (key))
1998-09-29 22:36:29 +00:00
#define RELKEY(table, key) if ((table)->callbacks.releaseKey) \
2004-10-12 21:28:27 +00:00
(*(table)->callbacks.releaseKey)(key)
1998-09-29 22:36:29 +00:00
static inline unsigned hashString(const void *param)
1998-09-29 22:36:29 +00:00
{
const char *key = param;
2009-08-20 00:59:40 +02:00
unsigned ret = 0;
unsigned ctr = 0;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
while (*key) {
2013-11-16 20:14:29 +01:00
ret ^= *key++ << ctr;
2009-08-20 00:59:40 +02:00
ctr = (ctr + 1) % sizeof(char *);
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return ret;
1998-09-29 22:36:29 +00:00
}
static inline unsigned hashPtr(const void *key)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
return ((size_t) key / sizeof(char *));
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
static void rellocateItem(WMHashTable * table, HashItem * item)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
unsigned h;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
h = HASH(table, item->key);
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
item->next = table->table[h];
table->table[h] = item;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
static void rebuildTable(WMHashTable * table)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
HashItem *next;
HashItem **oldArray;
int i;
int oldSize;
int newSize;
oldArray = table->table;
oldSize = table->size;
newSize = table->size * 2;
table->table = wmalloc(sizeof(char *) * newSize);
table->size = newSize;
for (i = 0; i < oldSize; i++) {
while (oldArray[i] != NULL) {
next = oldArray[i]->next;
rellocateItem(table, oldArray[i]);
oldArray[i] = next;
}
}
wfree(oldArray);
1998-09-29 22:36:29 +00:00
}
WMHashTable *WMCreateHashTable(const WMHashTableCallbacks callbacks)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
HashTable *table;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
table = wmalloc(sizeof(HashTable));
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
table->callbacks = callbacks;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
table->size = INITIAL_CAPACITY;
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
table->table = wmalloc(sizeof(HashItem *) * table->size);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return table;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
void WMResetHashTable(WMHashTable * table)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
HashItem *item, *tmp;
int i;
for (i = 0; i < table->size; i++) {
item = table->table[i];
while (item) {
tmp = item->next;
RELKEY(table, item->key);
wfree(item);
item = tmp;
}
}
table->itemCount = 0;
if (table->size > INITIAL_CAPACITY) {
wfree(table->table);
table->size = INITIAL_CAPACITY;
table->table = wmalloc(sizeof(HashItem *) * table->size);
2012-05-04 22:53:04 +02:00
} else {
memset(table->table, 0, sizeof(HashItem *) * table->size);
2009-08-20 00:59:40 +02:00
}
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
void WMFreeHashTable(WMHashTable * table)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
HashItem *item, *tmp;
int i;
for (i = 0; i < table->size; i++) {
item = table->table[i];
while (item) {
tmp = item->next;
RELKEY(table, item->key);
wfree(item);
item = tmp;
}
}
wfree(table->table);
wfree(table);
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
unsigned WMCountHashTable(WMHashTable * table)
{
2009-08-20 00:59:40 +02:00
return table->itemCount;
}
2014-09-02 11:17:31 +07:00
static HashItem *hashGetItem(WMHashTable *table, const void *key)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
unsigned h;
HashItem *item;
h = HASH(table, key);
item = table->table[h];
if (table->callbacks.keyIsEqual) {
while (item) {
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
break;
}
item = item->next;
}
} else {
while (item) {
if (key == item->key) {
break;
}
item = item->next;
}
}
2014-09-02 11:17:31 +07:00
return item;
}
void *WMHashGet(WMHashTable * table, const void *key)
{
HashItem *item;
item = hashGetItem(table, key);
if (!item)
2009-08-20 00:59:40 +02:00
return NULL;
2014-09-02 11:17:31 +07:00
return (void *)item->data;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
Bool WMHashGetItemAndKey(WMHashTable * table, const void *key, void **retItem, void **retKey)
{
2009-08-20 00:59:40 +02:00
HashItem *item;
2014-09-02 11:17:31 +07:00
item = hashGetItem(table, key);
if (!item)
2009-08-20 00:59:40 +02:00
return False;
2014-09-02 11:17:31 +07:00
if (retKey)
*retKey = (void *)item->key;
if (retItem)
*retItem = (void *)item->data;
return True;
}
2009-08-20 00:59:40 +02:00
void *WMHashInsert(WMHashTable * table, const void *key, const void *data)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
unsigned h;
HashItem *item;
int replacing = 0;
h = HASH(table, key);
/* look for the entry */
item = table->table[h];
if (table->callbacks.keyIsEqual) {
while (item) {
if ((*table->callbacks.keyIsEqual) (key, item->key)) {
replacing = 1;
break;
}
item = item->next;
}
} else {
while (item) {
if (key == item->key) {
replacing = 1;
break;
}
item = item->next;
}
}
if (replacing) {
const void *old;
old = item->data;
item->data = data;
RELKEY(table, item->key);
item->key = DUPKEY(table, key);
return (void *)old;
} else {
HashItem *nitem;
nitem = wmalloc(sizeof(HashItem));
nitem->key = DUPKEY(table, key);
nitem->data = data;
nitem->next = table->table[h];
table->table[h] = nitem;
table->itemCount++;
}
/* OPTIMIZE: put this in an idle handler. */
if (table->itemCount > table->size) {
1998-09-29 22:36:29 +00:00
#ifdef DEBUG0
2009-08-20 00:59:40 +02:00
printf("rebuilding hash table...\n");
1998-09-29 22:36:29 +00:00
#endif
2009-08-20 00:59:40 +02:00
rebuildTable(table);
1998-09-29 22:36:29 +00:00
#ifdef DEBUG0
2009-08-20 00:59:40 +02:00
printf("finished rebuild.\n");
1998-09-29 22:36:29 +00:00
#endif
2009-08-20 00:59:40 +02:00
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return NULL;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
static HashItem *deleteFromList(HashTable * table, HashItem * item, const void *key)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
HashItem *next;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if (item == NULL)
return NULL;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
if ((table->callbacks.keyIsEqual && (*table->callbacks.keyIsEqual) (key, item->key))
|| (!table->callbacks.keyIsEqual && key == item->key)) {
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
next = item->next;
RELKEY(table, item->key);
wfree(item);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
table->itemCount--;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return next;
}
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
item->next = deleteFromList(table, item->next, key);
1998-09-29 22:36:29 +00:00
2009-08-20 00:59:40 +02:00
return item;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
void WMHashRemove(WMHashTable * table, const void *key)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
unsigned h;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
h = HASH(table, key);
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
table->table[h] = deleteFromList(table, table->table[h], key);
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
WMHashEnumerator WMEnumerateHashTable(WMHashTable * table)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
WMHashEnumerator enumerator;
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
enumerator.table = table;
enumerator.index = 0;
enumerator.nextItem = table->table[0];
2004-10-12 21:28:27 +00:00
2009-08-20 00:59:40 +02:00
return enumerator;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
void *WMNextHashEnumeratorItem(WMHashEnumerator * enumerator)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
const void *data = NULL;
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorItem() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
data = ((HashItem *) enumerator->nextItem)->data;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
}
return (void *)data;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
void *WMNextHashEnumeratorKey(WMHashEnumerator * enumerator)
2001-01-11 02:35:21 +00:00
{
2009-08-20 00:59:40 +02:00
const void *key = NULL;
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorKey() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
key = ((HashItem *) enumerator->nextItem)->key;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
}
return (void *)key;
2001-01-11 02:35:21 +00:00
}
2009-08-20 00:59:40 +02:00
Bool WMNextHashEnumeratorItemAndKey(WMHashEnumerator * enumerator, void **item, void **key)
1998-09-29 22:36:29 +00:00
{
2009-08-20 00:59:40 +02:00
/* this assumes the table doesn't change between
* WMEnumerateHashTable() and WMNextHashEnumeratorItemAndKey() calls */
if (enumerator->nextItem == NULL) {
HashTable *table = enumerator->table;
while (++enumerator->index < table->size) {
if (table->table[enumerator->index] != NULL) {
enumerator->nextItem = table->table[enumerator->index];
break;
}
}
}
if (enumerator->nextItem) {
if (item)
*item = (void *)((HashItem *) enumerator->nextItem)->data;
if (key)
*key = (void *)((HashItem *) enumerator->nextItem)->key;
enumerator->nextItem = ((HashItem *) enumerator->nextItem)->next;
return True;
}
return False;
1998-09-29 22:36:29 +00:00
}
static Bool compareStrings(const void *param1, const void *param2)
1998-09-29 22:36:29 +00:00
{
const char *key1 = param1;
const char *key2 = param2;
2009-08-20 00:59:40 +02:00
return strcmp(key1, key2) == 0;
1998-09-29 22:36:29 +00:00
}
2009-08-20 00:59:40 +02:00
typedef void *(*retainFunc) (const void *);
typedef void (*releaseFunc) (const void *);
1998-09-29 22:36:29 +00:00
const WMHashTableCallbacks WMIntHashCallbacks = {
2009-08-20 00:59:40 +02:00
NULL,
NULL,
NULL,
NULL
1998-09-29 22:36:29 +00:00
};
const WMHashTableCallbacks WMStringHashCallbacks = {
hashString,
compareStrings,
2009-08-20 00:59:40 +02:00
(retainFunc) wstrdup,
(releaseFunc) wfree
1998-09-29 22:36:29 +00:00
};
const WMHashTableCallbacks WMStringPointerHashCallbacks = {
hashString,
compareStrings,
2009-08-20 00:59:40 +02:00
NULL,
NULL
1998-09-29 22:36:29 +00:00
};