archeus/src/std/hashtable.c

171 lines
4.6 KiB
C
Raw Normal View History

2022-10-27 15:16:54 -06:00
#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){
2022-10-27 15:16:54 -06:00
*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){
2022-10-27 15:16:54 -06:00
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;
}
2022-10-27 15:16:54 -06:00
ARC_HashtableNode_Destroy(node->node, external, userdata);
if(external){
external(node, userdata);
2022-10-27 15:16:54 -06:00
}
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){
2022-10-27 15:16:54 -06:00
for(uint32_t i = 0; i < htable->size; i++){
if(htable->nodes[i]){
ARC_HashtableNode_Destroy(htable->nodes[i], external, userdata);
2022-10-27 15:16:54 -06:00
}
}
free(htable->nodes);
free(htable);
}
void ARC_Hashtable_Add(ARC_Hashtable *htable, void *key, size_t keysize, void *data){
2022-10-27 15:16:54 -06:00
uint32_t size = 0;
htable->hash(key, &keysize, &size);
2022-10-27 15:16:54 -06:00
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
if(!bucket){
ARC_HashtableNode_Create(&bucket, key, &keysize, data);
htable->nodes[size % htable->size] = bucket;
return;
2022-10-27 15:16:54 -06:00
}
if(!htable->compare(bucket->key, &bucket->keysize, key, &keysize)){
arc_errno = ARC_ERRNO_EXISTS;
return;
}
2022-10-27 15:16:54 -06:00
while(bucket->node){
if(!htable->compare(bucket->node->key, &bucket->node->keysize, key, &keysize)){
arc_errno = ARC_ERRNO_EXISTS;
return;
}
2022-10-27 15:16:54 -06:00
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){
2022-10-27 15:16:54 -06:00
uint32_t size = 0;
htable->hash(key, &keysize, &size);
2022-10-27 15:16:54 -06:00
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
if(!bucket){
*data = NULL;
arc_errno = ARC_ERRNO_NULL;
return;
2022-10-27 15:16:54 -06:00
}
if(!htable->compare(bucket->key, &bucket->keysize, key, &keysize)){
*data = bucket->data;
return;
2022-10-27 15:16:54 -06:00
}
while(bucket->node){
if(!htable->compare(bucket->node->key, &bucket->node->keysize, key, &keysize)){
*data = bucket->node->data;
return;
2022-10-27 15:16:54 -06:00
}
2022-10-27 15:16:54 -06:00
bucket = bucket->node;
}
arc_errno = ARC_ERRNO_NULL;
2022-10-27 15:16:54 -06:00
}
void ARC_Hashtable_Remove(ARC_Hashtable *htable, void *key, size_t keysize, ARC_HashtableNode_DestroyExternal external, void *userdata){
2022-10-27 15:16:54 -06:00
uint32_t size = 0;
htable->hash(key, &keysize, &size);
2022-10-27 15:16:54 -06:00
ARC_HashtableNode *bucket = htable->nodes[size % htable->size];
if(!bucket){
arc_errno = ARC_ERRNO_NULL;
return;
}
2022-10-27 15:16:54 -06:00
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);
2022-10-27 15:16:54 -06:00
}
free(temp);
return;
2022-10-27 15:16:54 -06:00
}
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);
2022-10-27 15:16:54 -06:00
}
free(temp);
return;
2022-10-27 15:16:54 -06:00
}
bucket = bucket->node;
}
arc_errno = ARC_ERRNO_NULL;
2022-10-27 15:16:54 -06:00
}