flisp/src/hash.c
2025-03-14 22:54:43 +01:00

154 lines
3.2 KiB
C
Executable file

#include <string.h>
#include <assert.h>
#include <stdio.h>
#include "types.h"
#include "hash.h"
#include "config.h"
int heap_hashmap(HashMap *map, i32 size){
if(size < 32)
return 1;
map->curr_len = size;
map->buffer = malloc(sizeof(MapItem)*size);
map->bit_free = malloc(sizeof(u32)*size/32);
if(!map->buffer || !map->bit_free)
return 1;
memset(map->bit_free, 0, sizeof(u32)*size/32);
memset(map->buffer, 0, sizeof(MapItem)*size);
for(int i = 0; i < size; i++)
map->buffer[i].id = -1;
return 0;
}
void free_hashmap(HashMap *map){
free(map->buffer);
free(map->bit_free);
}
// ~djb2
i32 hash(i32 max, char *str){
if(!str)
return HASH_NULL;
u32 hsh = 5281;
char ch = str[0];
for(int i = 1; i < 32 && ch; i++){
hsh = (hsh << 5) ^ ch;
ch = str[i];
}
hsh %= max;
#if DEBUG == 2
assert(hsh < HASH_NULL);
#endif
return hsh;
}
i32 get_bit(u32 *bitmap, i32 pos){
return (bitmap[pos/32] >> (pos%32)) & 1;
}
void set_bit(u32 *bitmap, i32 pos){
bitmap[pos/32] |= (1<<(pos%32));
}
MapItem *hashmap_insert(HashMap *map, char *str){
#if DEBUG > 0
float load_factor = (float)(map->item_n+1)/(float)(map->curr_len);
//printf("%f\n", load_factor);
#if DEBUG == 1
assert(load_factor < 0.8);
#else
assert(load_factor < 0.7);
#endif
#endif
if(map->item_n+1 >= map->curr_len)
return NULL;
i32 hsh = hash(map->curr_len, str);
MapItem *match = hashmap_get(map, str);
if(match){
return match;
}
if(!map->bit_free[hsh/32]){
map->buffer[hsh].hash = hsh;
map->buffer[hsh].id = map->curr_id++;
strncpy(map->buffer[hsh].str, str, 32);
set_bit(map->bit_free, hsh);
map->item_n++;
return &map->buffer[hsh];
}
i32 pos = hsh;
i32 taken;
do {
taken = get_bit(map->bit_free, pos);
if(!taken)
break;
pos++;
} while(pos < map->curr_len && pos-hsh < RELOCATE_TRY_MAX);
#if DEBUG == 2
assert(!taken);
#endif
if(!taken){
map->buffer[pos].hash = hsh;
map->buffer[pos].id = map->curr_id++;
strncpy(map->buffer[pos].str, str, 32);
set_bit(map->bit_free, hsh);
map->item_n++;
return &map->buffer[pos];
}
return NULL;
}
MapItem *hashmap_get(HashMap *map, char *str){
i32 fhash = hash(map->curr_len, str);
i32 pos = fhash;
i32 match;
do {
i32 c_hash = map->buffer[pos].hash;
match = c_hash == fhash;
if(match)
match = !strncmp(str,map->buffer[pos].str,32);
pos++;
} while(!match && pos < map->curr_len && pos-fhash < RELOCATE_TRY_MAX);
pos--;
if(match)
return &map->buffer[pos];
else
return NULL;
}
void hashmap_remove(HashMap *map, char *str){
MapItem *ret = hashmap_get(map, str);
if(!ret)
return;
// Erase the existance of the entry
// (Literally 1984)
memset(ret, 0, sizeof(MapItem));
}
int cmp_mapitem_id(const void *_a, const void *_b){
const MapItem *a = _a;
const MapItem *b = _b;
return b->id - a->id;
}
void hashmap_remove_id(HashMap *map, i32 id){
i32 pos = 0;
int found = 0;
// TODO : Replace with bsearch again
for(int i = 0; i < map->curr_len && !found; i++){
found = map->buffer[pos++].id == id;
}
if(found)
memset(&map->buffer[--pos], 0, sizeof(MapItem));
}