199 lines
5.5 KiB
C
199 lines
5.5 KiB
C
#if __cplusplus
|
|
#define LC_Alignof(...) alignof(__VA_ARGS__)
|
|
#else
|
|
#define LC_Alignof(...) _Alignof(__VA_ARGS__)
|
|
#endif
|
|
|
|
#define LC_WRAP_AROUND_POWER_OF_2(x, pow2) (((x) & ((pow2)-1llu)))
|
|
|
|
#if defined(_MSC_VER)
|
|
#define LC_DebugBreak() (L->breakpoint_on_error && IsDebuggerPresent() && (__debugbreak(), 0))
|
|
#else
|
|
#define LC_DebugBreak() (L->breakpoint_on_error && (__builtin_trap(), 0))
|
|
#endif
|
|
#define LC_FatalError() (L->breakpoint_on_error ? LC_DebugBreak() : (LC_Exit(1), 0))
|
|
|
|
LC_FUNCTION void LC_IgnoreMessage(LC_Token *pos, char *str, int len) {
|
|
}
|
|
|
|
LC_FUNCTION void LC_SendErrorMessage(LC_Token *pos, LC_String s8) {
|
|
if (L->on_message) {
|
|
L->on_message(pos, s8.str, (int)s8.len);
|
|
} else {
|
|
if (pos) {
|
|
LC_String line = LC_GetTokenLine(pos);
|
|
LC_String fmt = LC_Format(L->arena, "%s(%d,%d): error: %.*s\n%.*s", (char *)pos->lex->file, pos->line, pos->column, LC_Expand(s8), LC_Expand(line));
|
|
LC_Print(fmt.str, fmt.len);
|
|
} else {
|
|
LC_Print(s8.str, s8.len);
|
|
}
|
|
}
|
|
LC_DebugBreak();
|
|
}
|
|
|
|
LC_FUNCTION void LC_SendErrorMessagef(LC_Lex *x, LC_Token *pos, const char *str, ...) {
|
|
LC_FORMAT(L->arena, str, s8);
|
|
LC_SendErrorMessage(pos, s8);
|
|
}
|
|
|
|
LC_FUNCTION void LC_HandleFatalError(void) {
|
|
if (L->on_fatal_error) {
|
|
L->on_fatal_error();
|
|
return;
|
|
}
|
|
LC_FatalError();
|
|
}
|
|
|
|
LC_FUNCTION void LC_MapReserve(LC_Map *map, int size) {
|
|
LC_Map old_map = *map;
|
|
|
|
LC_ASSERT(NULL, LC_IS_POW2(size));
|
|
map->len = 0;
|
|
map->cap = size;
|
|
LC_ASSERT(NULL, map->arena);
|
|
|
|
map->entries = LC_PushArray(map->arena, LC_MapEntry, map->cap);
|
|
|
|
if (old_map.entries) {
|
|
for (int i = 0; i < old_map.cap; i += 1) {
|
|
LC_MapEntry *it = old_map.entries + i;
|
|
if (it->key) LC_InsertMapEntry(map, it->key, it->value);
|
|
}
|
|
}
|
|
}
|
|
|
|
// FNV HASH (1a?)
|
|
LC_FUNCTION uint64_t LC_HashBytes(void *data, uint64_t size) {
|
|
uint8_t *data8 = (uint8_t *)data;
|
|
uint64_t hash = (uint64_t)14695981039346656037ULL;
|
|
for (uint64_t i = 0; i < size; i++) {
|
|
hash = hash ^ (uint64_t)(data8[i]);
|
|
hash = hash * (uint64_t)1099511628211ULL;
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
LC_FUNCTION uint64_t LC_HashMix(uint64_t x, uint64_t y) {
|
|
x ^= y;
|
|
x *= 0xff51afd7ed558ccd;
|
|
x ^= x >> 32;
|
|
return x;
|
|
}
|
|
|
|
LC_FUNCTION int LC_NextPow2(int v) {
|
|
v--;
|
|
v |= v >> 1;
|
|
v |= v >> 2;
|
|
v |= v >> 4;
|
|
v |= v >> 8;
|
|
v |= v >> 16;
|
|
v++;
|
|
return v;
|
|
}
|
|
|
|
LC_FUNCTION LC_MapEntry *LC_GetMapEntryEx(LC_Map *map, uint64_t key) {
|
|
LC_ASSERT(NULL, key);
|
|
if (map->len * 2 >= map->cap) {
|
|
LC_MapReserve(map, map->cap * 2);
|
|
}
|
|
|
|
uint64_t hash = LC_HashBytes(&key, sizeof(key));
|
|
if (hash == 0) hash += 1;
|
|
uint64_t index = LC_WRAP_AROUND_POWER_OF_2(hash, map->cap);
|
|
uint64_t i = index;
|
|
for (;;) {
|
|
LC_MapEntry *it = map->entries + i;
|
|
if (it->key == key || it->key == 0) {
|
|
return it;
|
|
}
|
|
|
|
i = LC_WRAP_AROUND_POWER_OF_2(i + 1, map->cap);
|
|
if (i == index) return NULL;
|
|
}
|
|
LC_ASSERT(NULL, !"invalid codepath");
|
|
}
|
|
|
|
LC_FUNCTION bool LC_InsertWithoutReplace(LC_Map *map, void *key, void *value) {
|
|
LC_MapEntry *entry = LC_GetMapEntryEx(map, (uint64_t)key);
|
|
if (entry->key != 0) return false;
|
|
|
|
map->len += 1;
|
|
entry->key = (uint64_t)key;
|
|
entry->value = (uint64_t)value;
|
|
return true;
|
|
}
|
|
|
|
LC_FUNCTION LC_MapEntry *LC_InsertMapEntry(LC_Map *map, uint64_t key, uint64_t value) {
|
|
LC_MapEntry *entry = LC_GetMapEntryEx(map, key);
|
|
if (entry->key == key) {
|
|
entry->value = value;
|
|
}
|
|
if (entry->key == 0) {
|
|
entry->key = key;
|
|
entry->value = value;
|
|
map->len += 1;
|
|
}
|
|
return entry;
|
|
}
|
|
|
|
LC_FUNCTION LC_MapEntry *LC_GetMapEntry(LC_Map *map, uint64_t key) {
|
|
LC_MapEntry *entry = LC_GetMapEntryEx(map, key);
|
|
if (entry && entry->key == key) {
|
|
return entry;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
LC_FUNCTION void LC_MapInsert(LC_Map *map, LC_String keystr, void *value) {
|
|
uint64_t key = LC_HashBytes(keystr.str, keystr.len);
|
|
LC_InsertMapEntry(map, key, (uint64_t)value);
|
|
}
|
|
|
|
LC_FUNCTION void *LC_MapGet(LC_Map *map, LC_String keystr) {
|
|
uint64_t key = LC_HashBytes(keystr.str, keystr.len);
|
|
LC_MapEntry *r = LC_GetMapEntry(map, key);
|
|
return r ? (void *)r->value : 0;
|
|
}
|
|
|
|
LC_FUNCTION void LC_MapInsertU64(LC_Map *map, uint64_t key, void *value) {
|
|
LC_InsertMapEntry(map, key, (uint64_t)value);
|
|
}
|
|
|
|
LC_FUNCTION void *LC_MapGetU64(LC_Map *map, uint64_t key) {
|
|
LC_MapEntry *r = LC_GetMapEntry(map, key);
|
|
return r ? (void *)r->value : 0;
|
|
}
|
|
|
|
LC_FUNCTION void *LC_MapGetP(LC_Map *map, void *key) {
|
|
return LC_MapGetU64(map, (uint64_t)key);
|
|
}
|
|
|
|
LC_FUNCTION void LC_MapInsertP(LC_Map *map, void *key, void *value) {
|
|
LC_InsertMapEntry(map, (uint64_t)key, (uint64_t)value);
|
|
}
|
|
|
|
LC_FUNCTION void LC_MapClear(LC_Map *map) {
|
|
if (map->len != 0) LC_MemoryZero(map->entries, map->cap * sizeof(LC_MapEntry));
|
|
map->len = 0;
|
|
}
|
|
|
|
LC_FUNCTION size_t LC_GetAlignOffset(size_t size, size_t align) {
|
|
size_t mask = align - 1;
|
|
size_t val = size & mask;
|
|
if (val) {
|
|
val = align - val;
|
|
}
|
|
return val;
|
|
}
|
|
|
|
LC_FUNCTION size_t LC_AlignUp(size_t size, size_t align) {
|
|
size_t result = size + LC_GetAlignOffset(size, align);
|
|
return result;
|
|
}
|
|
|
|
LC_FUNCTION size_t LC_AlignDown(size_t size, size_t align) {
|
|
size += 1; // Make sure when align is 8 doesn't get rounded down to 0
|
|
size_t result = size - (align - LC_GetAlignOffset(size, align));
|
|
return result;
|
|
}
|