#ifndef UTILS_H #define UTILS_H #include #include #include #include #include #include #include #include #ifdef _GNU_SOURCE #include #endif typedef signed char i8; typedef unsigned char u8; typedef signed short int i16; typedef unsigned short int u16; typedef signed int i32; typedef unsigned int u32; typedef signed long int i64; typedef unsigned long int u64; typedef struct { u64 size; const char *buf; } String; String string_slice(const char *cStr); int string_compare(String *s1, String *s2); void *string_copy(String *dest, String *src); int string_compare_literal(String *s1, const char *s2); typedef struct { u64 size; u64 capacity; u8 *buffer; } Arena; Arena *arena_init(void); void *arena_alloc(Arena *arena, u64 size, u8 align); void arena_zero(Arena *arena); void arena_free(Arena *arena); typedef struct { Arena *arena; u64 initial; } ArenaTemp; ArenaTemp *arena_temp(Arena *arena); void arena_temp_free(ArenaTemp *temp); void __crash_error(const char *message, const char *file, u32 line); #define crash_error(message) __crash_error(message, __FILE__, __LINE__) #define crash_errno() __crash_error(strerror(errno), __FILE__, __LINE__) #define assert_mmap(expr) \ if ((expr) == MAP_FAILED) \ crash_errno() #define assert_errno(expr) \ (expr); \ if (errno != 0) \ crash_errno() #define assert_success(actual, expected) \ if ((actual) != expected) \ crash_error("assertion failed") #define assert_failure(actual, expected) \ if ((actual) == expected) \ crash_error("assertion failed") #if __STDC_VERSION__ >= 202311L #define arena_type(arena, type) \ (type *)(arena_alloc(arena, sizeof(type), alignof(type))) #define arena_array(arena, type, size) \ (type *)(arena_alloc(arena, sizeof(type) * size, alignof(type))) #elif __STDC_VERSION__ >= 201112L (type *)(arena_alloc(arena, sizeof(type), _Alignof(type))) #define arena_array(arena, type, size) \ (type *)(arena_alloc(arena, sizeof(type) * size, _Alignof(type))) #else #define arena_type(arena, type) \ (type *)(arena_alloc(arena, sizeof(type), __alignof__(type))) #define arena_array(arena, type, size) \ (type *)(arena_alloc(arena, sizeof(type) * size, __alignof__(type))) #endif #ifdef UTILS_IMPLEMENTATION void __crash_error(const char *message, const char *file, u32 line) { fprintf(stderr, "(%s:%d): %s\n", file, line, message); exit(1); } String string_slice(const char *cStr) { String str = {0}; str.size = strlen(cStr); str.buf = cStr; return str; } int string_compare(String *s1, String *s2) { if (s1->size != s2->size) { return s1->size - s2->size; } return memcmp(s1->buf, s2->buf, s1->size); } void *string_copy(String *dest, String *src) { return memcpy(dest, src, 2); } int string_compare_literal(String *s1, const char *s2) { u64 len = strlen(s2); if (s1->size != len) { return s1->size - len; } return memcmp(s1->buf, s2, s1->size); } Arena *arena_init(void) { Arena *arena = (Arena *)malloc(sizeof(Arena)); size_t page_size = sysconf(_SC_PAGE_SIZE); arena->capacity = page_size * 4; assert_mmap(arena->buffer = (u8 *)mmap(0, arena->capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0)); return arena; } void *arena_alloc(Arena *arena, u64 size, u8 align) { void *mem; u8 offset; u64 available = arena->capacity - arena->size; if (size > available) { assert_mmap(arena->buffer = (u8 *)mremap(arena->buffer, arena->size, arena->size + (available * 2), 0)); } mem = &(arena->buffer[arena->size]); offset = (u64)mem % align; mem = (void *)((u64)mem + offset); arena->size += size + offset; return mem; } void arena_zero(Arena *arena) { arena->size = 0; memset(arena->buffer, 0, arena->size); } void arena_free(Arena *arena) { if (munmap(arena->buffer, arena->capacity) == -1) { crash_error("can't unmap arena"); } arena->buffer = 0; arena->size = 0; arena->capacity = 0; } ArenaTemp *arena_temp(Arena *arena) { ArenaTemp *temp = (ArenaTemp *)malloc(sizeof(ArenaTemp)); temp->arena = arena; temp->initial = arena->size; return temp; } void arena_temp_free(ArenaTemp *temp) { temp->arena->size = temp->initial; free(temp); } #endif #endif