#define GB_NO_DEFER #define GB_IMPLEMENTATION #include "gb/gb.h" gbAllocator heap_allocator(void) { return gb_heap_allocator(); } #include "string.cpp" #include "array.cpp" gb_global String global_module_path = {0}; gb_global bool global_module_path_set = false; String get_module_dir() { if (global_module_path_set) { return global_module_path; } Array(wchar_t) path_buf; array_init_count(&path_buf, heap_allocator(), 300); isize len = 0; for (;;) { len = GetModuleFileNameW(NULL, &path_buf.e[0], path_buf.count); if (len == 0) { return make_string(NULL, 0); } if (len < path_buf.count) { break; } array_resize(&path_buf, 2*path_buf.count + 300); } gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); GetModuleFileNameW(NULL, text, len); String path = string16_to_string(heap_allocator(), make_string16(text, len)); for (isize i = path.len-1; i >= 0; i--) { u8 c = path.text[i]; if (c == '/' || c == '\\') { break; } path.len--; } global_module_path = path; global_module_path_set = true; gb_temp_arena_memory_end(tmp); array_free(&path_buf); return path; } String path_to_fullpath(gbAllocator a, String s) { gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&string_buffer_arena); String16 string16 = string_to_string16(string_buffer_allocator, s); String result = {0}; DWORD len = GetFullPathNameW(string16.text, 0, NULL, NULL); if (len != 0) { wchar_t *text = gb_alloc_array(string_buffer_allocator, wchar_t, len+1); GetFullPathNameW(string16.text, len, text, NULL); text[len] = 0; result = string16_to_string(a, make_string16(text, len)); } gb_temp_arena_memory_end(tmp); return result; } // Hasing typedef enum HashKeyKind { HashKey_Default, HashKey_String, HashKey_Pointer, } HashKeyKind; typedef struct HashKey { HashKeyKind kind; u64 key; union { String string; // if String, s.len > 0 void * ptr; }; } HashKey; gb_inline HashKey hashing_proc(void const *data, isize len) { HashKey h = {HashKey_Default}; h.kind = HashKey_Default; // h.key = gb_murmur64(data, len); h.key = gb_fnv64a(data, len); return h; } gb_inline HashKey hash_string(String s) { HashKey h = hashing_proc(s.text, s.len); h.kind = HashKey_String; h.string = s; return h; } gb_inline HashKey hash_pointer(void *ptr) { HashKey h = {HashKey_Default}; h.key = cast(u64)cast(uintptr)ptr; h.ptr = ptr; h.kind = HashKey_Default; return h; } bool hash_key_equal(HashKey a, HashKey b) { if (a.key == b.key) { // NOTE(bill): If two string's hashes collide, compare the strings themselves if (a.kind == HashKey_String) { if (b.kind == HashKey_String) { return str_eq(a.string, b.string); } return false; } return true; } return false; } i64 next_pow2(i64 n) { if (n <= 0) { return 0; } n--; n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; n |= n >> 32; n++; return n; } i64 prev_pow2(i64 n) { if (n <= 0) { return 0; } n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16; n |= n >> 32; return n - (n >> 1); } i16 f32_to_f16(f32 value) { union { u32 i; f32 f; } v; i32 i, s, e, m; v.f = value; i = (i32)v.i; s = (i >> 16) & 0x00008000; e = ((i >> 23) & 0x000000ff) - (127 - 15); m = i & 0x007fffff; if (e <= 0) { if (e < -10) return cast(i16)s; m = (m | 0x00800000) >> (1 - e); if (m & 0x00001000) m += 0x00002000; return cast(i16)(s | (m >> 13)); } else if (e == 0xff - (127 - 15)) { if (m == 0) { return cast(i16)(s | 0x7c00); /* NOTE(bill): infinity */ } else { /* NOTE(bill): NAN */ m >>= 13; return cast(i16)(s | 0x7c00 | m | (m == 0)); } } else { if (m & 0x00001000) { m += 0x00002000; if (m & 0x00800000) { m = 0; e += 1; } } if (e > 30) { float volatile f = 1e12f; int j; for (j = 0; j < 10; j++) f *= f; /* NOTE(bill): Cause overflow */ return cast(i16)(s | 0x7c00); } return cast(i16)(s | (e << 10) | (m >> 13)); } } #define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++) // Doubly Linked Lists #define DLIST_SET(curr_element, next_element) do { \ (curr_element)->next = (next_element); \ (curr_element)->next->prev = (curr_element); \ (curr_element) = (curr_element)->next; \ } while (0) #define DLIST_APPEND(root_element, curr_element, next_element) do { \ if ((root_element) == NULL) { \ (root_element) = (curr_element) = (next_element); \ } else { \ DLIST_SET(curr_element, next_element); \ } \ } while (0) //////////////////////////////////////////////////////////////// // // Generic Data Structures // //////////////////////////////////////////////////////////////// #define MAP_TYPE String #define MAP_FUNC map_string_ #define MAP_NAME MapString #include "map.c" #define MAP_TYPE bool #define MAP_FUNC map_bool_ #define MAP_NAME MapBool #include "map.c" #define MAP_TYPE isize #define MAP_FUNC map_isize_ #define MAP_NAME MapIsize #include "map.c" #if 0 #ifndef MAP_FIND_RESULT #define MAP_FIND_RESULT typedef struct MapFindResult { isize hash_index; isize entry_prev; isize entry_index; } MapFindResult; #endif template struct MapEntry { HashKey key; isize next; T value; }; template struct Map { Array(isize) hashes; Array(MapEntry) entries; }; template void map_init (Map *h, gbAllocator a); template void map_init_with_reserve(Map *h, gbAllocator a, isize capacity); template void map_destroy (Map *h); template T * map_get (Map *h, HashKey key); template void map_set (Map *h, HashKey key, T value); template void map_remove (Map *h, HashKey key); template void map_clear (Map *h); template void map_grow (Map *h); template void map_rehash (Map *h, isize new_count); template MapEntry *multi_map_find_first(Map *h, HashKey key); template MapEntry *multi_map_find_next (Map *h, MapEntry *e); template isize multi_map_count (Map *h, HashKey key); template void multi_map_get_all (Map *h, HashKey key, T *items); template void multi_map_insert (Map *h, HashKey key, T value); template void multi_map_remove (Map *h, HashKey key, MapEntry *e); template void multi_map_remove_all(Map *h, HashKey key); template gb_inline void map_init(Map *h, gbAllocator a) { array_init(&h->hashes, a); array_init(&h->entries, a); } template gb_inline void map_init_with_reserve(Map *h, gbAllocator a, isize capacity) { array_init_reserve(&h->hashes, a, capacity); array_init_reserve(&h->entries, a, capacity); } template gb_inline void map_destroy(Map *h) { array_free(&h->entries); array_free(&h->hashes); } template gb_internal isize map__add_entry(Map *h, HashKey key) { MapEntry e = {}; e.key = key; e.next = -1; array_add(&h->entries, e); return h->entries.count-1; } template gb_internal MapFindResult map__find(Map *h, HashKey key) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = key.key % h->hashes.count; fr.entry_index = h->hashes.e[fr.hash_index]; while (fr.entry_index >= 0) { if (hash_key_equal(h->entries.e[fr.entry_index].key, key)) { return fr; } fr.entry_prev = fr.entry_index; fr.entry_index = h->entries.e[fr.entry_index].next; } } return fr; } template gb_internal MapFindResult map__find(Map *h, MapEntry *e) { MapFindResult fr = {-1, -1, -1}; if (h->hashes.count > 0) { fr.hash_index = e->key.key % h->hashes.count; fr.entry_index = h->hashes.e[fr.hash_index]; while (fr.entry_index >= 0) { if (&h->entries.e[fr.entry_index] == e) { return fr; } fr.entry_prev = fr.entry_index; fr.entry_index = h->entries.e[fr.entry_index].next; } } return fr; } template gb_internal bool map__full(Map *h) { return 0.75f * h->hashes.count <= h->entries.count; } template gb_inline void map_grow(Map *h) { isize new_count = GB_ARRAY_GROW_FORMULA(h->entries.count); map_rehash(h, new_count); } template void map_rehash(Map *h, isize new_count) { isize i, j; Map nh = {0}; map_init(&nh, h->hashes.allocator); array_resize(&nh.hashes, new_count); array_reserve(&nh.entries, h->entries.count); for (i = 0; i < new_count; i++) { nh.hashes.e[i] = -1; } for (i = 0; i < h->entries.count; i++) { MapEntry *e = &h->entries.e[i]; MapFindResult fr; if (nh.hashes.count == 0) { map_grow(&nh); } fr = map__find(&nh, e->key); j = map__add_entry(&nh, e->key); if (fr.entry_prev < 0) { nh.hashes.e[fr.hash_index] = j; } else { nh.entries.e[fr.entry_prev].next = j; } nh.entries.e[j].next = fr.entry_index; nh.entries.e[j].value = e->value; if (map__full(&nh)) { map_grow(&nh); } } map_destroy(h); *h = nh; } template gb_inline T *map_get(Map *h, HashKey key) { isize index = map__find(h, key).entry_index; if (index >= 0) return &h->entries.e[index].value; return NULL; } template void map_set(Map *h, HashKey key, T value) { isize index; MapFindResult fr; if (h->hashes.count == 0) map_grow(h); fr = map__find(h, key); if (fr.entry_index >= 0) { index = fr.entry_index; } else { index = map__add_entry(h, key); if (fr.entry_prev >= 0) { h->entries.e[fr.entry_prev].next = index; } else { h->hashes.e[fr.hash_index] = index; } } h->entries.e[index].value = value; if (map__full(h)) map_grow(h); } template void map__erase(Map *h, MapFindResult fr) { if (fr.entry_prev < 0) { h->hashes.e[fr.hash_index] = h->entries.e[fr.entry_index].next; } else { h->entries.e[fr.entry_prev].next = h->entries.e[fr.entry_index].next; } if (fr.entry_index == h->entries.count-1) { array_pop(&h->entries); return; } h->entries.e[fr.entry_index] = h->entries.e[h->entries.count-1]; MapFindResult last = map__find(h, h->entries.e[fr.entry_index].key); if (last.entry_prev >= 0) { h->entries.e[last.entry_prev].next = fr.entry_index; } else { h->hashes.e[last.hash_index] = fr.entry_index; } } template void map_remove(Map *h, HashKey key) { MapFindResult fr = map__find(h, key); if (fr.entry_index >= 0) { map__erase(h, fr); } } template gb_inline void map_clear(Map *h) { gb_array_clear(h->hashes); gb_array_clear(h->entries); } template MapEntry *multi_map_find_first(Map *h, HashKey key) { isize i = map__find(h, key).entry_index; if (i < 0) { return NULL; } return &h->entries.e[i]; } template MapEntry *multi_map_find_next(Map *h, MapEntry *e) { isize i = e->next; while (i >= 0) { if (hash_key_equal(h->entries.e[i].key, e->key)) { return &h->entries.e[i]; } i = h->entries.e[i].next; } return NULL; } template isize multi_map_count(Map *h, HashKey key) { isize count = 0; auto *e = multi_map_find_first(h, key); while (e != NULL) { count++; e = multi_map_find_next(h, e); } return count; } template void multi_map_get_all(Map *h, HashKey key, T *items) { isize i = 0; auto *e = multi_map_find_first(h, key); while (e != NULL) { items[i++] = e->value; e = multi_map_find_next(h, e); } } template void multi_map_insert(Map *h, HashKey key, T value) { if (h->hashes.count == 0) { map_grow(h); } MapFindResult fr = map__find(h, key); isize i = map__add_entry(h, key); if (fr.entry_prev < 0) { h->hashes.e[fr.hash_index] = i; } else { h->entries.e[fr.entry_prev].next = i; } h->entries.e[i].next = fr.entry_index; h->entries.e[i].value = value; if (map__full(h)) { map_grow(h); } } template void multi_map_remove(Map *h, HashKey key, MapEntry *e) { MapFindResult fr = map__find(h, e); if (fr.entry_index >= 0) { map__erase(h, fr); } } template void multi_map_remove_all(Map *h, HashKey key) { while (map_get(h, key) != NULL) { map_remove(h, key); } } #endif