Skip to content

Commit d2bce08

Browse files
committed
Simplified arena allocator
1 parent 00b8e94 commit d2bce08

4 files changed

Lines changed: 191 additions & 89 deletions

File tree

AGENTS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
CLAUDE.md

CLAUDE.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Project overview
6+
7+
extlib is a **single-header C99 library** (`extlib.h`) providing data structures and utilities missing
8+
from the C standard library: dynamic arrays, hashmaps, string slices/buffers, arenas, a context
9+
system for allocators/logging, and cross-platform IO. It supports no-std and wasm targets.
10+
11+
## Build and test commands
12+
13+
```sh
14+
make # Build all examples
15+
make test # Build and run test suite
16+
make format # Format all .c/.h files with clang-format
17+
make clean # Remove built artifacts
18+
./test/test <suite> # Run only one test suite (e.g. ./test/test array)
19+
```
20+
21+
The test binary accepts an optional suite name argument to filter tests. Suite names match the first
22+
argument of `CTEST(suite, name)` in `test/test.c` (e.g. `alloc`, `temp`, `arena`, `array`, `sb`,
23+
`slice`, `hmap`, `defer`, `logging`, `io`).
24+
25+
Compiler flags: `-Wall -Wextra -Wno-override-init -std=c99 -ggdb`.
26+
27+
## Architecture
28+
29+
The entire library lives in `extlib.h` (~3700 lines). In exactly one translation unit, define
30+
`EXTLIB_IMPL` before including the header to emit the implementation. All other files just
31+
`#include "extlib.h"` for declarations only.
32+
33+
### Sections
34+
35+
Navigate to a component by grepping for `SECTION: <name>`. The header is organized as declarations
36+
first (lines ~65–1210), then `#ifdef EXTLIB_IMPL` implementations (~1710–2800), then debug helpers
37+
and shorthand aliases (~2800–3580).
38+
39+
Key sections: **Context**, **Allocators**, **Temporary allocator**, **Arena allocator**, **Dynamic
40+
array**, **Hashmap**, **String buffer**, **String slice**, **IO**.
41+
42+
### Naming convention
43+
44+
Every public symbol has an `ext_` / `Ext_` / `EXT_` prefix. Unless `EXTLIB_NO_SHORTHANDS` is
45+
defined, unprefixed aliases are also available (e.g. `array_push` for `ext_array_push`, `Arena` for
46+
`Ext_Arena`). **Always use the unprefixed shorthand names** in code that consumes extlib. Always
47+
use prefixed one for new implementations inside extlib.
48+
49+
### Generic containers (dynamic array and hashmap)
50+
51+
Both dynamic arrays and hashmaps are "generic" via a struct-layout convention — the user defines a
52+
struct with specific fields and passes a pointer to the container macros:
53+
54+
**Dynamic array** — struct must have fields: `T* items; size_t size, capacity; Allocator* allocator;`
55+
56+
**Hashmap** — entry struct must have fields: `K key; V value;` and the map struct must have:
57+
`Entry* entries; size_t* hashes; size_t size, capacity; Allocator* allocator;`
58+
59+
Hashmaps come in three key-type flavors: integer keys (`hmap_put`/`hmap_get`), C-string keys
60+
(`hmap_put_cstr`/`hmap_get_cstr`), and `StringSlice` keys (`hmap_put_ss`/`hmap_get_ss`).
61+
62+
### Context and allocators
63+
64+
A thread-local `ext_context` pointer controls the default allocator and log level. Use
65+
`push_context` / `pop_context` (or `PUSH_ALLOCATOR` / `PUSH_CONTEXT` scope macros) to temporarily
66+
swap allocators. Individual containers can also override the allocator via their `.allocator` field.
67+
68+
### Adding new functions — checklist
69+
70+
Every new public function needs four pieces:
71+
72+
1. **Declaration** (in the declarations section, ~65–1210) with `ext_` prefix and doc comment
73+
2. **Implementation** (inside `#ifdef EXTLIB_IMPL`, ~1710–2800) using `ext_` prefix
74+
3. **Shorthand alias** (in `#ifndef EXTLIB_NO_SHORTHANDS`, ~3480–3580) mapping unprefixed to prefixed
75+
4. **Tests** in `test/test.c` using the shorthand names
76+
77+
For functions with a `StringSlice` parameter, also add a `_cstr` convenience variant that converts
78+
via `ext_ss_from_cstr` and delegates.
79+
80+
### Declaration ordering constraints
81+
82+
The `Ext_StringSlice` typedef lives at the start of the String slice section (~line 1064). Any
83+
declaration that references `Ext_StringSlice` must appear **after** this typedef. This means
84+
StringBuffer functions that take `Ext_StringSlice` parameters (e.g. `ext_sb_append_path`) must be
85+
declared in or after the String slice declaration section, not in the StringBuffer section above it.
86+
87+
### `EXTLIB_NO_STD` / WASM considerations
88+
89+
When adding functions that use libc utilities (e.g. `toupper`, `tolower`, `isspace`), you must
90+
provide fallback implementations in the `#else` branch of the `#ifndef EXTLIB_NO_STD` guard. The
91+
WASM build target (`make` builds `examples/03_arena.wasm`) compiles with `EXTLIB_WASM` which
92+
implies `EXTLIB_NO_STD`, and will fail if libc functions are used without fallbacks.
93+
94+
The `<ctype.h>` include and its no-std fallbacks (`isspace`, `toupper`, `tolower`) live at the top
95+
of the String buffer implementation section (around line 2330).
96+
97+
### Platform-conditional code
98+
99+
Use `#ifdef EXT_WINDOWS` for Windows-specific behavior (e.g. backslash path separators). The
100+
platform macros (`EXT_WINDOWS`, `EXT_LINUX`, `EXT_POSIX`, etc.) are defined near the top of the
101+
header (~line 84). When testing platform-specific code on Linux, temporarily remove the `#ifdef`
102+
guard, verify, then restore it.
103+
104+
### Testing
105+
106+
Tests use the [ctest](https://github.com/bvdberg/ctest) framework (`test/ctest.h`). The test
107+
harness in `test/test.c` wraps all tests in a tracking allocator that detects memory leaks — any
108+
un-freed allocations cause a test failure.
109+
110+
Always run both `make test` (test suite) and `make` (all examples including WASM) to verify changes.
111+
The WASM build often catches missing no-std fallbacks that the native build doesn't.

0 commit comments

Comments
 (0)