Real hashmap

This commit is contained in:
attilavs2 2025-03-05 14:38:36 +01:00
parent 238bc31425
commit e0d78813d0
14 changed files with 70 additions and 52 deletions

0
.gitignore vendored Normal file → Executable file
View file

3
Makefile Normal file → Executable file
View file

@ -3,7 +3,7 @@
OUTNAME = flisp OUTNAME = flisp
CFLAGS = -O0 -Wall -Wextra -g -pipe CFLAGS = -O0 -Wall -Wextra -g -pipe
CC = gcc CC = gcc
@ -27,6 +27,7 @@ windef:
$(eval OUTPUT = "$(OUTNAME).exe") $(eval OUTPUT = "$(OUTNAME).exe")
$(eval BUILD_DIR = build-win) $(eval BUILD_DIR = build-win)
$(eval LDFLAGS = $(LDFLAGS_WIN)) $(eval LDFLAGS = $(LDFLAGS_WIN))
$(eval CFLAGS += -mno-ms-bitfields -D win)
builddir: builddir:
@- mkdir $(BUILD_DIR) @- mkdir $(BUILD_DIR)

0
examples/hello_world.flsp Normal file → Executable file
View file

0
examples/more_or_less.flsp Normal file → Executable file
View file

0
spec.md Normal file → Executable file
View file

21
src/byte_defs.h Normal file → Executable file
View file

@ -73,41 +73,44 @@ typedef struct {
typedef struct { typedef struct {
u8 __padding[2];
u32 value; u32 value;
u8 __padding[2];
} PACKED Value4B; } PACKED Value4B;
typedef struct { typedef struct {
u16 len;
u32 pos; // Offset from stack allocator u32 pos; // Offset from stack allocator
u16 len;
} PACKED ValueArray; } PACKED ValueArray;
typedef struct { typedef struct {
u8 len; PACKED union {
union {
char str[5]; char str[5];
struct { PACKED struct {
u8 __padding;
u32 pos; u32 pos;
u8 __padding;
}; };
}; };
u8 len;
} PACKED ValueStr; } PACKED ValueStr;
typedef struct { typedef struct {
uint is_array : 1;
uint type : 15;
PACKED union { PACKED union {
Value4B v4B; Value4B v4B;
ValueArray varray; ValueArray varray;
}; };
uint is_array : 1;
uint type : 15;
} PACKED Value; } PACKED Value;
#ifndef win
_Static_assert(sizeof(Value) == 8); _Static_assert(sizeof(Value) == 8);
#endif

9
src/bytecode.c Executable file
View file

@ -0,0 +1,9 @@
#include <string.h>
#include <stdlib.h>
#include "types.h"
#include "byte_defs.h"
void run_bytecode(){
}

0
src/code_defs.h Normal file → Executable file
View file

0
src/config.h Normal file → Executable file
View file

0
src/fixed.h Normal file → Executable file
View file

51
src/hash.c Normal file → Executable file
View file

@ -10,6 +10,7 @@ int heap_hashmap(HashMap *map, i32 size){
if(size < 32) if(size < 32)
return 1; return 1;
map->curr_len = size; map->curr_len = size;
map->curr_id = 0;
map->buffer = malloc(sizeof(MapItem)*size); map->buffer = malloc(sizeof(MapItem)*size);
map->bit_free = malloc(sizeof(u32)*size/32); map->bit_free = malloc(sizeof(u32)*size/32);
@ -27,7 +28,7 @@ void free_hashmap(HashMap *map){
} }
// ~djb2 // ~djb2
u32 hash(i32 max, char *str){ i32 hash(i32 max, char *str){
if(!str) if(!str)
return HASH_NULL; return HASH_NULL;
u32 hsh = 5281; u32 hsh = 5281;
@ -51,44 +52,42 @@ void set_bit(u32 *bitmap, i32 pos){
bitmap[pos/32] |= (1<<(pos%32)); bitmap[pos/32] |= (1<<(pos%32));
} }
u32 hashmap_insert(HashMap *map, char *str){ i32 hashmap_insert(HashMap *map, char *str){
#if DEBUG > 0 #if DEBUG > 0
float load_factor = (float)(map->item_n+1)/(float)(map->curr_len); float load_factor = (float)(map->item_n+1)/(float)(map->curr_len);
//printf("%f\n", load_factor); //printf("%f\n", load_factor);
#if DEBUG == 1 #if DEBUG == 1
assert(load_factor < 0.95);
#else
assert(load_factor < 0.8); assert(load_factor < 0.8);
#else
assert(load_factor < 0.7);
#endif #endif
#endif #endif
if(map->item_n+1 >= map->curr_len) if(map->item_n+1 >= map->curr_len)
return HASH_NULL; return HASH_NULL;
u32 hsh = hash(map->curr_len, str); i32 hsh = hash(map->curr_len, str);
char *match = hashmap_get(map, hsh); i32 match = hashmap_get(map, str);
if(match){ if(match > 0){
if(!strncmp(match, str, 32)) return match;
return hsh;
} }
if(!map->bit_free[hsh/32]){ if(!map->bit_free[hsh/32]){
printf("[ncan]");
map->buffer[hsh].hash = hsh; map->buffer[hsh].hash = hsh;
map->buffer[hsh].id = map->curr_id++;
strncpy(map->buffer[hsh].str, str, 32); strncpy(map->buffer[hsh].str, str, 32);
set_bit(map->bit_free, hsh); set_bit(map->bit_free, hsh);
map->item_n++; map->item_n++;
return hsh; return map->buffer[hsh].id;
} }
u32 pos = hsh; i32 pos = hsh;
i32 taken; i32 taken;
do { do {
taken = get_bit(map->bit_free, pos); taken = get_bit(map->bit_free, pos);
if(!taken) if(!taken)
break; break;
pos++; pos++;
} while(pos < map->curr_len); } while(pos < map->curr_len && pos-hsh < RELOCATE_TRY_MAX);
printf("(%d %d)", hsh, pos);
#if DEBUG == 2 #if DEBUG == 2
assert(!taken); assert(!taken);
@ -96,28 +95,32 @@ u32 hashmap_insert(HashMap *map, char *str){
if(!taken){ if(!taken){
map->buffer[pos].hash = hsh; map->buffer[pos].hash = hsh;
strncpy(map->buffer[hsh].str, str, 32); map->buffer[pos].id = map->curr_id++;
strncpy(map->buffer[pos].str, str, 32);
set_bit(map->bit_free, hsh); set_bit(map->bit_free, hsh);
map->item_n++; map->item_n++;
return hsh; return map->buffer[pos].id;
} }
return HASH_NULL; return HASH_NULL;
} }
char *hashmap_get(HashMap *map, u32 fhash){ i32 hashmap_get(HashMap *map, char *str){
u32 pos = fhash; i32 fhash = hash(map->curr_len, str);
i32 pos = fhash;
i32 match; i32 match;
do { do {
u32 c_hash = map->buffer[pos].hash; i32 c_hash = map->buffer[pos].hash;
match = c_hash == fhash; match = c_hash == fhash;
printf("[%d %d]", c_hash, fhash); if(match)
match = !strncmp(str,map->buffer[pos].str,32);
pos++; pos++;
} while(!match && pos < map->curr_len); } while(!match && pos < map->curr_len && pos-fhash < RELOCATE_TRY_MAX);
pos--; pos--;
if(match) if(match)
return map->buffer[pos].str; return map->buffer[pos].id;
else else
return NULL; return -1;
} }

16
src/hash.h Normal file → Executable file
View file

@ -7,12 +7,13 @@
#define HASH_NULL 0xFFFFFF #define HASH_NULL 0xFFFFFF
#define LOAD_EXTEND fix(0.7) #define RELOCATE_TRY_MAX 32
typedef struct { typedef struct {
u32 hash; // Hashs are internally 24bit for bytecode ops i32 hash; // Hashs are internally 24bit for bytecode ops
char str[32]; char str[32];
i32 id;
} MapItem; } MapItem;
@ -20,8 +21,9 @@ typedef struct {
MapItem *buffer; MapItem *buffer;
u32 *bit_free; // Bit map to track usage u32 *bit_free; // Bit map to track usage
u32 curr_len; i32 curr_len;
u32 item_n; i32 item_n;
i32 curr_id;
} HashMap; } HashMap;
@ -30,9 +32,9 @@ int heap_hashmap(HashMap *map, i32 size);
void free_hashmap(HashMap *map); void free_hashmap(HashMap *map);
// Max is max value of hash // Max is max value of hash
u32 hash(i32 max, char *str); i32 hash(i32 max, char *str);
// Returns hash - if error returns HASH_NULL // Returns hash - if error returns HASH_NULL
u32 hashmap_insert(HashMap *map, char *str); i32 hashmap_insert(HashMap *map, char *str);
char *hashmap_get(HashMap *map, u32 hash); i32 hashmap_get(HashMap *map, char *str);

18
src/main.c Normal file → Executable file
View file

@ -11,9 +11,10 @@
#define STR_N 20 #define STR_N 20
int main(){ int main(){
HashMap map; HashMap map;
if(heap_hashmap(&map, 256)){ if(heap_hashmap(&map, 256) ){
printf("Failed to alloc hashmap"); printf("Failed to alloc hashmap\n");
return 1; return 1;
} }
@ -40,19 +41,14 @@ int main(){
"b" "b"
}; };
char *strings2[STR_N]; int ids[STR_N];
int hashs[STR_N];
for(int i = 0; i < STR_N; i++) for(int i = 0; i < STR_N; i++)
hashs[i] = hashmap_insert(&map, strings[i]); ids[i] = hashmap_insert(&map, strings[i]);
for(int i = 0; i < STR_N; i++){
strings2[i] = hashmap_get(&map, hashs[i]);
printf("%d : %s\n", hashs[i], strings2[i]);
}
i32 res = 0; i32 res = 0;
for(int i = 0; i < STR_N; i++){ for(int i = 0; i < STR_N; i++){
res += strncmp(strings[i], strings2[i], 32); res = ids[i] - hashmap_get(&map, strings[i]);
printf("%s : %d:%d\n", strings[i], hashmap_get(&map, strings[i]),ids[i]);
} }
assert(!res); assert(!res);

4
src/types.h Normal file → Executable file
View file

@ -13,5 +13,9 @@ typedef uint64_t u64;
typedef unsigned int uint; typedef unsigned int uint;
#ifdef win
#define PACKED __attribute__((gcc_struct)) __attribute__((__packed__))
#else
#define PACKED __attribute__((__packed__)) #define PACKED __attribute__((__packed__))
#endif