Created
          July 31, 2025 12:07 
        
      - 
      
- 
        Save grom358/ceafb6f90ccb83eb827e53740cb32a75 to your computer and use it in GitHub Desktop. 
    Random foundation layer C
  
        
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
  | typedef struct { | |
| size_t len; | |
| const char* ptr; | |
| } StringView; | |
| void libc_panic(int code, const char* file_name, const char* function_name, int line_no) { | |
| fprintf(stderr, "FATAL ERROR at %s:%s:%d - %s\n", | |
| file_name, function_name, line_no, strerror(code)); | |
| exit(EXIT_FAILURE); | |
| } | |
| typedef struct ArenaChunk { | |
| struct ArenaChunk* next; | |
| size_t used; | |
| size_t capacity; | |
| char memory[]; | |
| } ArenaChunk; | |
| struct Arena { | |
| size_t initial_chunk_size; | |
| size_t next_chunk_multiple; | |
| ArenaChunk* head; | |
| }; | |
| void arena_init(Arena** out_arena, size_t initial_chunk_size) { | |
| Arena* arena = malloc(sizeof(Arena)); | |
| if (!arena) LIBC_PANIC(ENOMEM); | |
| arena->initial_chunk_size = initial_chunk_size; | |
| arena->next_chunk_multiple = 1; | |
| arena->head = NULL; | |
| *out_arena = arena; | |
| } | |
| void arena_destroy(Arena* arena) { | |
| ArenaChunk* chunk = arena->head; | |
| while (chunk) { | |
| ArenaChunk* next = chunk->next; | |
| free(chunk); | |
| chunk = next; | |
| } | |
| free(arena); | |
| } | |
| void arena_reset(Arena* arena) { | |
| for (ArenaChunk* chunk = arena->head; chunk; chunk = chunk->next) { | |
| chunk->used = 0; | |
| } | |
| } | |
| static inline void* try_alloc_from_chunk(ArenaChunk* chunk, size_t size, size_t alignment) { | |
| uintptr_t base = (uintptr_t)(chunk->memory + chunk->used); | |
| uintptr_t aligned = (base + alignment - 1) & ~(uintptr_t)(alignment - 1); | |
| size_t padding = aligned - base; | |
| size_t total = padding + size; | |
| if (chunk->used + total > chunk->capacity) { | |
| return NULL; | |
| } | |
| chunk->used += total; | |
| return (void*)aligned; | |
| } | |
| void* arena_alloc_array(Arena* arena, size_t count, size_t size, size_t alignment) { | |
| size_t total_size = count * size; | |
| assert(alignment && (alignment & (alignment - 1)) == 0); | |
| for (ArenaChunk* chunk = arena->head; chunk; chunk = chunk->next) { | |
| void* ptr = try_alloc_from_chunk(chunk, total_size, alignment); | |
| if (ptr) return ptr; | |
| } | |
| size_t chunk_capacity = arena->initial_chunk_size * arena->next_chunk_multiple; | |
| size_t min_required = total_size + alignment; | |
| while (chunk_capacity < min_required) { | |
| arena->next_chunk_multiple *= 2; | |
| chunk_capacity = arena->initial_chunk_size * arena->next_chunk_multiple; | |
| } | |
| ArenaChunk* new_chunk = malloc(sizeof(ArenaChunk) + chunk_capacity); | |
| if (!new_chunk) LIBC_PANIC(ENOMEM); | |
| new_chunk->next = arena->head; | |
| new_chunk->capacity = chunk_capacity; | |
| new_chunk->used = 0; | |
| arena->head = new_chunk; | |
| arena->next_chunk_multiple *= 2; | |
| return try_alloc_from_chunk(new_chunk, total_size, alignment); | |
| } | |
| void hex_dump(FILE* out, const char* data, size_t len) { | |
| const size_t bytes_per_line = 16; | |
| for (size_t i = 0; i < len; i += bytes_per_line) { | |
| fprintf(out, "%08zx ", i); | |
| // Print hex bytes | |
| for (size_t j = 0; j < bytes_per_line; ++j) { | |
| if (i + j < len) { | |
| fprintf(out, "%02x ", (unsigned char)data[i + j]); | |
| } else { | |
| fprintf(out, " "); | |
| } | |
| // Extra space in middle | |
| if (j == 7) fputc(' ', out); | |
| } | |
| fputc(' ', out); | |
| // Print ASCII representation | |
| for (size_t j = 0; j < bytes_per_line && i + j < len; ++j) { | |
| char c = data[i + j]; | |
| fputc(isprint((unsigned char)c) ? c : '.', out); | |
| } | |
| fputc('\n', out); | |
| } | |
| } | |
| StringView string_view_from_cstr(const char* cstr) { | |
| return (StringView){ .len = strlen(cstr), .ptr = cstr }; | |
| } | |
| // Minimum size for 128 length String = sizeof(struct String) + 128 + \0 | |
| #define ARENA_SPRINTF_MIN 144 | |
| String arena_vsprintf(Arena* arena, const char* fmt, va_list args) { | |
| assert(fmt != NULL); | |
| va_list args_copy; | |
| va_copy(args_copy, args); | |
| size_t struct_size = sizeof(struct String); | |
| assert(arena->capacity >= arena->used); | |
| size_t remaining = TRUNC8(arena->capacity - arena->used); | |
| size_t used_before = arena->used; | |
| int needed; | |
| if (remaining > ARENA_SPRINTF_MIN) { | |
| // Attempt to write string without growing the arena | |
| size_t str_capacity = remaining - struct_size - 1; | |
| struct String* str = arena_alloc(arena, remaining); | |
| needed = vsnprintf(str->data, str_capacity + 1, fmt, args_copy); | |
| va_end(args_copy); | |
| if (needed >= 0 && (size_t)needed <= str_capacity) { | |
| // It fit. Shrink to used space. | |
| size_t needed_t = (size_t) needed; | |
| arena->used = used_before + ALIGN8(needed_t + struct_size + 1); | |
| str->len = needed_t; | |
| return str; | |
| } | |
| arena->used = used_before; | |
| } else { | |
| needed = vsnprintf(NULL, 0, fmt, args_copy); | |
| va_end(args_copy); | |
| } | |
| if (needed < 0) { | |
| FATAL(EINVAL); | |
| } | |
| size_t needed_t = (size_t) needed; | |
| size_t total_size = struct_size + needed_t + 1; | |
| struct String* str = arena_alloc(arena, total_size); | |
| vsnprintf(str->data, needed_t + 1, fmt, args); | |
| str->len = needed_t; | |
| return str; | |
| } | |
  
    Sign up for free
    to join this conversation on GitHub.
    Already have an account?
    Sign in to comment