170 lines
4.6 KiB
C
170 lines
4.6 KiB
C
#include "arc/std/hashtable.h"
|
|
|
|
#include "arc/std/errno.h"
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
|
|
struct ARC_Hashtable {
|
|
uint32_t size;
|
|
ARC_HashtableNode **nodes;
|
|
ARC_Hashtable_Hash hash;
|
|
ARC_Hashtable_KeyCompare compare;
|
|
};
|
|
|
|
void CRC32(void *key, size_t *keysize, uint32_t *hashval){
|
|
*hashval = 0xffffffff;
|
|
|
|
for(size_t i = 0; i < *keysize; i++){
|
|
uint8_t value = *(((uint8_t *)key) + i);
|
|
for(uint8_t j = 0; j < 8; j++){
|
|
uint8_t flag = (uint8_t)((value ^ *hashval) & 1);
|
|
*hashval >>= 1;
|
|
if(flag){ *hashval ^= 0xEDB888320; }
|
|
value >>= 1;
|
|
}
|
|
}
|
|
|
|
*hashval = ~*hashval;
|
|
}
|
|
|
|
int8_t ARC_Default_Key_Compare(void *key1, size_t *key1size, void *key2, size_t *key2size){
|
|
return key1 == key2;
|
|
}
|
|
|
|
void ARC_HashtableNode_Create(ARC_HashtableNode **node, void *key, size_t *keysize, void *data){
|
|
*node = (ARC_HashtableNode *) malloc(sizeof(ARC_HashtableNode));
|
|
(*node)->key = key;
|
|
(*node)->keysize = *keysize;
|
|
(*node)->data = data;
|
|
(*node)->node = NULL;
|
|
}
|
|
|
|
void ARC_HashtableNode_Destroy(ARC_HashtableNode *node, ARC_HashtableNode_DestroyExternal external, void *userdata){
|
|
if(node == NULL){
|
|
return;
|
|
}
|
|
|
|
ARC_HashtableNode_Destroy(node->node, external, userdata);
|
|
|
|
if(external){
|
|
external(node, userdata);
|
|
}
|
|
|
|
free(node);
|
|
}
|
|
|
|
void ARC_Hashtable_Create(ARC_Hashtable **htable, uint32_t bucketsize, ARC_Hashtable_Hash hash, ARC_Hashtable_KeyCompare compare){
|
|
*htable = (ARC_Hashtable *) malloc(sizeof(ARC_Hashtable));
|
|
(*htable)->size = bucketsize;
|
|
(*htable)->nodes = (ARC_HashtableNode **) calloc(bucketsize, sizeof(ARC_HashtableNode *));
|
|
(*htable)->hash = (hash)? hash : CRC32;
|
|
(*htable)->compare = (compare)? compare : ARC_Default_Key_Compare;
|
|
}
|
|
|
|
void ARC_Hashtable_Destroy(ARC_Hashtable *htable, ARC_HashtableNode_DestroyExternal external, void *userdata){
|
|
for(uint32_t i = 0; i < htable->size; i++){
|
|
if(htable->nodes[i]){
|
|
ARC_HashtableNode_Destroy(htable->nodes[i], external, userdata);
|
|
}
|
|
}
|
|
|
|
free(htable->nodes);
|
|
free(htable);
|
|
}
|
|
|
|
void ARC_Hashtable_Add(ARC_Hashtable *htable, void *key, size_t keysize, void *data){
|
|
uint32_t size = 0;
|
|
htable->hash(key, &keysize, &size);
|
|
|
|
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
|
|
if(!bucket){
|
|
ARC_HashtableNode_Create(&bucket, key, &keysize, data);
|
|
htable->nodes[size % htable->size] = bucket;
|
|
return;
|
|
}
|
|
|
|
if(!htable->compare(bucket->key, &bucket->keysize, key, &keysize)){
|
|
arc_errno = ARC_ERRNO_EXISTS;
|
|
return;
|
|
}
|
|
|
|
while(bucket->node){
|
|
if(!htable->compare(bucket->node->key, &bucket->node->keysize, key, &keysize)){
|
|
arc_errno = ARC_ERRNO_EXISTS;
|
|
return;
|
|
}
|
|
|
|
bucket = bucket->node;
|
|
}
|
|
|
|
ARC_HashtableNode_Create(&(bucket->node), key, &keysize, data);
|
|
}
|
|
|
|
void ARC_Hashtable_Get(ARC_Hashtable *htable, void *key, size_t keysize, void **data){
|
|
uint32_t size = 0;
|
|
htable->hash(key, &keysize, &size);
|
|
|
|
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
|
|
if(!bucket){
|
|
*data = NULL;
|
|
arc_errno = ARC_ERRNO_NULL;
|
|
return;
|
|
}
|
|
|
|
if(!htable->compare(bucket->key, &bucket->keysize, key, &keysize)){
|
|
*data = bucket->data;
|
|
return;
|
|
}
|
|
|
|
while(bucket->node){
|
|
if(!htable->compare(bucket->node->key, &bucket->node->keysize, key, &keysize)){
|
|
*data = bucket->node->data;
|
|
return;
|
|
}
|
|
|
|
bucket = bucket->node;
|
|
}
|
|
|
|
arc_errno = ARC_ERRNO_NULL;
|
|
}
|
|
|
|
void ARC_Hashtable_Remove(ARC_Hashtable *htable, void *key, size_t keysize, ARC_HashtableNode_DestroyExternal external, void *userdata){
|
|
uint32_t size = 0;
|
|
htable->hash(key, &keysize, &size);
|
|
|
|
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
|
|
if(!bucket){
|
|
arc_errno = ARC_ERRNO_NULL;
|
|
return;
|
|
}
|
|
|
|
if(!htable->compare(bucket->key, &bucket->keysize, key, &keysize)){
|
|
ARC_HashtableNode *temp = bucket;
|
|
htable->nodes[size % htable->size] = bucket->node;
|
|
|
|
if(external){
|
|
external(temp, userdata);
|
|
}
|
|
|
|
free(temp);
|
|
return;
|
|
}
|
|
|
|
while(bucket->node){
|
|
if(!htable->compare(bucket->node->key, &bucket->node->keysize, key, &keysize)){
|
|
ARC_HashtableNode *temp = bucket->node;
|
|
bucket->node = bucket->node->node;
|
|
|
|
if(external){
|
|
external(temp, userdata);
|
|
}
|
|
|
|
free(temp);
|
|
return;
|
|
}
|
|
|
|
bucket = bucket->node;
|
|
}
|
|
|
|
arc_errno = ARC_ERRNO_NULL;
|
|
}
|