Files
bongo/src/libs/util/hashtable.c
T
2026-07-18 22:29:44 +02:00

358 lines
9.1 KiB
C

/****************************************************************************
* <Novell-copyright>
* Copyright (c) 2005 Novell, Inc. All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of version 2 of the GNU General Public License
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, contact Novell, Inc.
*
* To contact Novell about this file by physical or electronic mail, you
* may find current contact information at www.novell.com.
* </Novell-copyright>
****************************************************************************/
#include <config.h>
#include <xpl.h>
#include <bongoutil.h>
#include <assert.h>
uint32_t
BongoStringHash(const void *key)
{
const unsigned char *s = key;
uint32_t b = 1;
uint32_t h = 0;
for (; *s; s++) {
h += b * tolower(*s);
b = (b << 5) - b;
}
return h;
}
int
BongoStringCompare(const void *keya, const void *keyb)
{
return strcmp(keya, keyb);
}
void *
BongoHashtableGet(const BongoHashtable *table, const void *key)
{
struct BongoHashtableEntry *entry;
uint32_t hashcode;
const CompareFunction compfunc = table->compfunc;
hashcode = table->hashfunc(key);
for (entry = table->buckets[hashcode % table->bucketcount];
entry;
entry = entry->next)
{
if (entry->key == key ||
(compfunc && !compfunc(entry->key, key)))
{
return entry->value;
}
}
return NULL;
}
/* returns 0 on success */
int
BongoHashtablePutNoReplace(BongoHashtable *table, void *key, void *value)
{
struct BongoHashtableEntry *entry;
int bucket;
entry = MemMalloc (sizeof(struct BongoHashtableEntry));
if (!entry) {
return -1;
}
entry->hashcode = table->hashfunc(key);
entry->key = key;
entry->value = value;
bucket = entry->hashcode % table->bucketcount;
entry->next = table->buckets[bucket];
table->buckets[bucket] = entry;
table->itemcount++;
return 0;
}
/* returns 0 on success
if keydeletefunc is not null, it is used to free the old key
if oldvalue is not null, returns previous value (if set)
*/
int
BongoHashtablePut(BongoHashtable *table, void *key, void *value)
{
struct BongoHashtableEntry *entry;
uint32_t hashcode;
const CompareFunction compfunc = table->compfunc;
assert(key != NULL);
hashcode = table->hashfunc(key);
for (entry = table->buckets[hashcode % table->bucketcount];
entry;
entry = entry->next)
{
if (entry->key == key ||
(compfunc && !compfunc(entry->key, key)))
{
if (table->keydeletefunc) {
table->keydeletefunc (entry->key);
}
if (table->valuedeletefunc) {
table->valuedeletefunc(entry->value);
}
entry->key = key;
entry->value = value;
return 0;
}
}
return BongoHashtablePutNoReplace(table, key, value);
}
/* returns value */
void *
BongoHashtableRemoveFull(BongoHashtable *table, const void *key, BOOL deleteKey, BOOL deleteValue)
{
struct BongoHashtableEntry *entry;
struct BongoHashtableEntry *last;
uint32_t hashcode;
const CompareFunction compfunc = table->compfunc;
hashcode = table->hashfunc(key);
for (last = NULL, entry = table->buckets[hashcode % table->bucketcount];
entry;
last = entry, entry = entry->next)
{
if (entry->key == key ||
(compfunc && !compfunc(entry->key, key)))
{
void *value = entry->value;
if (deleteKey && table->keydeletefunc) {
table->keydeletefunc(entry->key);
}
if (deleteValue && table->valuedeletefunc) {
table->valuedeletefunc(entry->value);
}
table->itemcount--;
if (last) {
last->next = entry->next;
} else {
table->buckets[hashcode % table->bucketcount] = entry->next;
}
MemFree(entry);
return value;
}
}
return NULL;
}
void *
BongoHashtableRemoveKeyValue(BongoHashtable *table, const void *key, void *value,
BOOL deleteKey, BOOL deleteValue)
{
struct BongoHashtableEntry *entry;
struct BongoHashtableEntry *last;
uint32_t hashcode;
const CompareFunction compfunc = table->compfunc;
hashcode = table->hashfunc(key);
for (last = NULL, entry = table->buckets[hashcode % table->bucketcount];
entry;
last = entry, entry = entry->next)
{
if ((entry->key == key || (compfunc && !compfunc(entry->key, key)))
&& (entry->value == value))
{
if (deleteKey && table->keydeletefunc) {
table->keydeletefunc(entry->key);
}
if (deleteValue && table->valuedeletefunc) {
table->valuedeletefunc(entry->value);
}
table->itemcount--;
if (last) {
last->next = entry->next;
} else {
table->buckets[hashcode % table->bucketcount] = entry->next;
}
MemFree(entry);
return value;
}
}
return NULL;
}
void *
BongoHashtableRemove(BongoHashtable *table, const void *key)
{
return BongoHashtableRemoveFull(table, key, TRUE, TRUE);
}
BongoHashtable *
BongoHashtableCreateFull(int buckets,
HashFunction hashfunc, CompareFunction compfunc,
DeleteFunction keydeletefunc, DeleteFunction valuedeletefunc)
{
BongoHashtable *table;
const int size = ALIGN_SIZE(sizeof(BongoHashtable), ALIGNMENT) + buckets * ALIGN_SIZE(sizeof(struct BongoHashtableEntry *), ALIGNMENT);
table = MemMalloc(size);
if (!table) {
return NULL;
}
memset(table, 0, size);
table->bucketcount = buckets;
table->hashfunc = hashfunc;
table->compfunc = compfunc;
table->keydeletefunc = keydeletefunc;
table->valuedeletefunc = valuedeletefunc;
//memset(&(table->buckets[0]), 0, buckets * ALIGN_SIZE(sizeof(struct BongoHashtableEntry *), ALIGNMENT));
return table;
}
BongoHashtable *
BongoHashtableCreate(int buckets,
HashFunction hashfunc, CompareFunction compfunc)
{
return BongoHashtableCreateFull(buckets, hashfunc, compfunc, NULL, NULL);
}
void
BongoHashtableForeach(BongoHashtable *table, HashtableForeachFunc func, void *data)
{
int i;
struct BongoHashtableEntry *entry;
for (i = 0; i < table->bucketcount; i++) {
entry = table->buckets[i];
while (entry) {
func(entry->key, entry->value, data);
entry = entry->next;
}
}
}
BOOL
BongoHashtableIterFirst(BongoHashtable *table, BongoHashtableIter *iter)
{
for (iter->bucket = 0; iter->bucket < table->bucketcount; iter->bucket++) {
iter->entry = table->buckets[iter->bucket];
if (iter->entry) {
iter->key = iter->entry->key;
iter->value = iter->entry->value;
return TRUE;
}
}
iter->key = iter->value = NULL;
return FALSE;
}
BOOL
BongoHashtableIterNext(BongoHashtable *table, BongoHashtableIter *iter)
{
iter->entry = iter->entry->next;
if (iter->entry) {
iter->key = iter->entry->key;
iter->value = iter->entry->value;
return TRUE;
}
for (iter->bucket++; iter->bucket < table->bucketcount; iter->bucket++) {
iter->entry = table->buckets[iter->bucket];
if (iter->entry) {
iter->key = iter->entry->key;
iter->value = iter->entry->value;
return TRUE;
}
}
iter->key = iter->value = NULL;
return FALSE;
}
int
BongoHashtableSize(BongoHashtable *table)
{
return table->itemcount;
}
void
BongoHashtableClear(BongoHashtable *table)
{
BongoHashtableClearFull(table, TRUE, TRUE);
}
void
BongoHashtableClearFull(BongoHashtable *table, BOOL deleteKeys, BOOL deleteValues)
{
int i;
struct BongoHashtableEntry *entry;
for (i = 0; i < table->bucketcount; i++) {
entry = table->buckets[i];
while (entry) {
struct BongoHashtableEntry *tmp = entry->next;
if (deleteKeys && table->keydeletefunc) {
table->keydeletefunc(entry->key);
}
if (deleteValues && table->valuedeletefunc) {
table->valuedeletefunc(entry->value);
}
MemFree(entry);
entry = tmp;
}
table->buckets[i] = NULL;
}
table->itemcount = 0;
}
void
BongoHashtableDelete(BongoHashtable *table)
{
BongoHashtableClear(table);
MemFree(table);
}