#include #include #include #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)); }