366 lines
7.9 KiB
C
366 lines
7.9 KiB
C
|
|
function S64
|
|
clamp_top_s64(S64 val, S64 max){
|
|
if(val>max)return max;
|
|
return val;
|
|
}
|
|
|
|
function SizeU
|
|
max_sizeu(SizeU a, SizeU b){
|
|
if(a>b) return a;
|
|
return b;
|
|
}
|
|
|
|
function U64
|
|
hash_fnv(String string) {
|
|
U64 hash = (U64)14695981039346656037ULL;
|
|
for (U64 i = 0; i < string.len; i++) {
|
|
hash = hash ^ (U64)(string.str[i]);
|
|
hash = hash * (U64)1099511628211ULL;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
function U64
|
|
hash_u64(U64 x) {
|
|
x *= 0xff51afd7ed558ccd;
|
|
x ^= x >> 32;
|
|
return x;
|
|
}
|
|
|
|
function U64
|
|
hash_ptr(const void *ptr) {
|
|
return hash_u64((uintptr_t)ptr);
|
|
}
|
|
|
|
function U64
|
|
hash_mix(U64 x, U64 y) {
|
|
x ^= y;
|
|
x *= 0xff51afd7ed558ccd;
|
|
x ^= x >> 32;
|
|
return x;
|
|
}
|
|
|
|
function U64
|
|
is_pow2(U64 x) {
|
|
assert(x != 0);
|
|
B32 result = (x & (x - 1llu)) == 0;
|
|
return result;
|
|
}
|
|
|
|
function U64
|
|
wrap_around_pow2(U64 x, U64 power_of_2) {
|
|
assert(is_pow2(power_of_2));
|
|
U64 r = (((x)&((power_of_2)-1llu)));
|
|
return r;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Strings
|
|
//-----------------------------------------------------------------------------
|
|
global String string_empty;
|
|
|
|
function B32
|
|
string_compare(String a, String b){
|
|
if(a.len != b.len)
|
|
return false;
|
|
for(S64 i = 0; i < a.len; i++){
|
|
if(a.str[i] != b.str[i])
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
function U8
|
|
char_to_lower(U8 c){
|
|
if(c >= 'A' && c <= 'Z')
|
|
c += 32;
|
|
return c;
|
|
}
|
|
|
|
function U8
|
|
char_to_upper(U8 c){
|
|
if(c >= 'a' && c <= 'z')
|
|
c -= 32;
|
|
return c;
|
|
}
|
|
|
|
function B32
|
|
string_is_empty(String a){
|
|
B32 result = a.len == 0;
|
|
return result;
|
|
}
|
|
|
|
function String
|
|
string_to_lower(Arena *arena, String string){
|
|
String result = arena_push_string_copy(arena, string);
|
|
for(S64 i = 0; i < string.len; i++){
|
|
result.str[i] = char_to_lower(result.str[i]);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Per Vognsen's like Map to pointers
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct Map_Key_Val{
|
|
U64 key;
|
|
void *value;
|
|
}Map_Key_Val;
|
|
|
|
typedef struct Map{
|
|
Map_Key_Val *data;
|
|
int len;
|
|
int cap;
|
|
}Map;
|
|
|
|
function void map_insert_u64(Map *map, U64 key, void *val);
|
|
function int max_int(int a, int b);
|
|
|
|
|
|
#include <stdlib.h>
|
|
function void
|
|
map_grow(Map *map, int new_size){
|
|
new_size = max_int(16, new_size);
|
|
assert(new_size > map->cap);
|
|
assert(is_pow2(new_size));
|
|
Map new_map = {
|
|
.data = calloc(new_size, sizeof(Map_Key_Val)),
|
|
.cap = new_size,
|
|
};
|
|
for(int i = 0; i < map->cap; i++){
|
|
if(map->data[i].key){
|
|
map_insert_u64(&new_map, map->data[i].key, map->data[i].value);
|
|
}
|
|
}
|
|
if(map->data) free(map->data);
|
|
*map = new_map;
|
|
}
|
|
|
|
function void
|
|
map_insert_u64(Map *map, U64 key, void *val){
|
|
assert(val);
|
|
if(key == 0) key++;
|
|
if((2*map->len) + 1 > map->cap){
|
|
map_grow(map, 2*map->cap);
|
|
}
|
|
U64 hash = hash_u64(key);
|
|
U64 index = wrap_around_pow2(hash, map->cap);
|
|
U64 i = index;
|
|
for(;;){
|
|
if(map->data[i].key == 0){
|
|
map->len++;
|
|
map->data[i].key = key;
|
|
map->data[i].value = val;
|
|
return;
|
|
}
|
|
else if(map->data[i].key == key){
|
|
map->data[i].value = val;
|
|
return;
|
|
}
|
|
|
|
i = wrap_around_pow2(i+1, map->cap);
|
|
if(i == map->cap){
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
function void *
|
|
map_get_u64(Map *map, U64 key){
|
|
if(map->len == 0) return 0;
|
|
if(key == 0) key++;
|
|
U64 hash = hash_u64(key);
|
|
U64 index = wrap_around_pow2(hash, map->cap);
|
|
U64 i = index;
|
|
for(;;){
|
|
if(map->data[i].key == key){
|
|
return map->data[i].value;
|
|
}
|
|
else if(map->data[i].key == 0){
|
|
return 0;
|
|
}
|
|
|
|
i = wrap_around_pow2(i+1, map->cap);
|
|
if(i == map->cap){
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
function void *
|
|
map_get(Map *map, void *pointer){
|
|
return map_get_u64(map, (U64)pointer);
|
|
}
|
|
|
|
function void
|
|
map_insert(Map *map, void *key, void *value){
|
|
map_insert_u64(map, (U64)key, value);
|
|
}
|
|
|
|
function void
|
|
map_test(){
|
|
Map map = {0};
|
|
const SizeU size = 1025;
|
|
for(SizeU i = 1; i < size; i++){
|
|
map_insert_u64(&map, i, (void *)i);
|
|
}
|
|
for(SizeU i = 1; i < size; i++){
|
|
SizeU val = (SizeU)map_get_u64(&map, i);
|
|
assert(val == i);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// Array
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct Array_Head{
|
|
int cap, len;
|
|
}Array_Head;
|
|
|
|
#define array_get_head(x) (((Array_Head *)(x)) - 1)
|
|
#define array_cap(x) array_get_head(x)->cap
|
|
#define array_len(x) array_get_head(x)->len
|
|
#define array_push(arr,i) (array_grow((void **)&arr, sizeof(arr[0])), (arr)[array_len(arr)++] = (i))
|
|
#define array_init(arr,cap) array__init((void **)&arr,sizeof(arr[0]), cap)
|
|
|
|
|
|
function void
|
|
array__init(void **array, SizeU sizeof_item, int cap){
|
|
Array_Head *head = malloc(sizeof_item*cap + sizeof(Array_Head));
|
|
head->cap = cap;
|
|
head->len = 0;
|
|
*array = head + 1;
|
|
}
|
|
|
|
function void
|
|
array_grow(void **array, SizeU sizeof_item){
|
|
if(*array == 0){
|
|
array__init(array, sizeof_item, 16);
|
|
}
|
|
else if(array_len(*array) + 1 > array_cap(*array)){
|
|
Array_Head *head = array_get_head(*array);
|
|
SizeU len = head->len;
|
|
SizeU cap = head->cap * 2;
|
|
head = realloc(head, sizeof_item*cap + sizeof(Array_Head));
|
|
head->cap = cap;
|
|
head->len = len;
|
|
*array = head + 1;
|
|
}
|
|
}
|
|
|
|
function void
|
|
array_test(){
|
|
int *array = 0;
|
|
for(int i = 0; i < 100; i++){
|
|
array_push(array, i);
|
|
}
|
|
for(int i = 0; i < 100; i++){
|
|
assert(array[i] == i);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
// String interning
|
|
//-----------------------------------------------------------------------------
|
|
typedef struct Table_Index{
|
|
U64 hash;
|
|
U64 index;
|
|
U64 iter;
|
|
U64 max_size;
|
|
}Table_Index;
|
|
|
|
typedef struct Intern_String{
|
|
String s;
|
|
}Intern_String;
|
|
|
|
typedef struct Intern_Table{
|
|
S64 interns_in_bytes;
|
|
S64 interns_inserted;
|
|
S64 interns_max;
|
|
Intern_String *interns;
|
|
Arena *arena;
|
|
}Intern_Table;
|
|
|
|
function Intern_Table
|
|
intern_table(Arena *arena, SizeU size){
|
|
Intern_Table result = {0};
|
|
result.arena = arena;
|
|
result.interns = arena_push_array(arena, Intern_String, size);
|
|
result.interns_max = size;
|
|
return result;
|
|
}
|
|
|
|
function Table_Index
|
|
table_index_from_hash(U64 hash, U64 max_size){
|
|
Table_Index result = {0};
|
|
result.hash = hash;
|
|
result.index = result.hash % max_size;
|
|
result.iter = result.index;
|
|
result.max_size = max_size;
|
|
return result;
|
|
}
|
|
|
|
function Table_Index
|
|
table_index_from_string(String string, U64 max_size){
|
|
U64 hash = hash_fnv(string);
|
|
Table_Index result = table_index_from_hash(hash, max_size);
|
|
return result;
|
|
}
|
|
|
|
function B32
|
|
table_index_advance(Table_Index *index){
|
|
index->iter = wrap_around_pow2(index->iter + 1, index->max_size);
|
|
B32 result = index->iter == index->index;
|
|
return result;
|
|
}
|
|
|
|
function Intern_String
|
|
intern_string(Intern_Table *p, String string){
|
|
Intern_String result = {0};
|
|
Table_Index index = table_index_from_string(string, p->interns_max);
|
|
for(;;){
|
|
Intern_String *intern = p->interns + index.iter;
|
|
if(intern->s.str == 0){
|
|
result.s = arena_push_string_copy(p->arena, string);
|
|
p->interns_in_bytes += string.len;
|
|
p->interns_inserted += 1;
|
|
*intern = result;
|
|
break;
|
|
}
|
|
else if(string_compare(intern->s, string)){
|
|
result = *intern;
|
|
break;
|
|
}
|
|
|
|
if (table_index_advance(&index))
|
|
break;
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
function B32
|
|
intern_compare(Intern_String a, Intern_String b){
|
|
B32 result = a.s.str == b.s.str;
|
|
return result;
|
|
}
|
|
|
|
function void
|
|
intern_test(){
|
|
Arena *scratch = arena_begin_scratch();
|
|
Intern_Table table = intern_table(scratch, 512);
|
|
assert(intern_compare(intern_string(&table, lit("Thing")),
|
|
intern_string(&table, lit("Thing"))));
|
|
assert(!intern_compare(intern_string(&table, lit("Thing")),
|
|
intern_string(&table, lit("No_Thing"))));
|
|
assert(intern_compare(intern_string(&table, lit("No_Thing")),
|
|
intern_string(&table, lit("No_Thing"))));
|
|
|
|
}
|
|
|
|
|
|
|
|
|