Skip to content

Instantly share code, notes, and snippets.

@grom358
Created July 31, 2025 12:07
Show Gist options
  • Save grom358/ceafb6f90ccb83eb827e53740cb32a75 to your computer and use it in GitHub Desktop.
Save grom358/ceafb6f90ccb83eb827e53740cb32a75 to your computer and use it in GitHub Desktop.
Random foundation layer C
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