Update AGENTS.md
This commit is contained in:
@@ -28,6 +28,9 @@ All code follows the patterns established in `src/wapp/`. The project prefix is
|
||||
| Internal/static funcs | `_` + camelCase | `_resolveTopology`, `_execCmd` |
|
||||
| File-scope globals | `_` + camelCase | `_default_allocator` |
|
||||
| File-scope constants | SCREAMING_SNAKE | `MAX_NODE_NAME` |
|
||||
| Variables | snake_case | `vertex_count`, `edge_node` |
|
||||
|
||||
- **Variable names**: Prefer descriptive names (e.g. `vertex_count` over `vc`, `edge_node` over `en`). Short names (`i`, `j`, `n`) are acceptable only in tight loop counters or trivial index variables. Avoid single-letter names in non-trivial scopes, and avoid abbreviated names that require the reader to hold a mental dictionary.
|
||||
|
||||
### Formatting
|
||||
|
||||
@@ -118,6 +121,55 @@ prefer SoA layouts, batch processing, and minimise pointer chasing. Keep
|
||||
the DAG in contiguous arrays (e.g. adjacency lists packed in flat buffers)
|
||||
rather than individually allocated linked structures.
|
||||
|
||||
### Graph / adjacency lists
|
||||
|
||||
Adjacency list nodes must be **separately allocated from the vertex array**.
|
||||
Never use the vertex struct itself as a linked-list node in another vertex's
|
||||
adjacency chain — that shares the `next` pointer between two roles (vertex state
|
||||
vs. edge linking) and causes edges to splice into unintended chains.
|
||||
|
||||
```c
|
||||
// correct — per-edge copy on the arena
|
||||
static void addEdge(PrGraph *g, const WpAllocator *alloc, u64 from, u64 to) {
|
||||
PrVertex *src = &g->vertices[from];
|
||||
PrVertex *dst = wpMemAllocatorAlloc(alloc, sizeof(PrVertex));
|
||||
if (!dst) { /* handle OOM */ return; }
|
||||
dst->id = g->vertices[to].id;
|
||||
dst->value = g->vertices[to].value;
|
||||
dst->next = src->next;
|
||||
src->next = dst;
|
||||
}
|
||||
|
||||
// wrong — reuses the destination vertex as the list node
|
||||
static void addEdge_bad(PrGraph *g, u64 from, u64 to) {
|
||||
PrVertex *src = &g->vertices[from];
|
||||
PrVertex *dest = &g->vertices[to];
|
||||
dest->next = src->next;
|
||||
src->next = dest; // overwrites dest->next used elsewhere
|
||||
}
|
||||
```
|
||||
|
||||
Arena bump allocation (`wpMemAllocatorAlloc`) is the natural fit for building
|
||||
graph structures: per-edge nodes live in the arena and are freed in one shot
|
||||
when the arena is destroyed.
|
||||
|
||||
Always NULL-check the result of `wpMemAllocatorAlloc` — even arena allocators
|
||||
can fail if the backing buffer is exhausted.
|
||||
|
||||
### WpArray usage
|
||||
|
||||
| Scenario | API | Size must be… |
|
||||
|----------|-----|---------------|
|
||||
| Stack (local, short-lived) | `wpArrayWithCapacity` | compile-time constant |
|
||||
| Heap (arena-backed) | `wpArrayAllocCapacity` | runtime value |
|
||||
|
||||
`wpArrayWithCapacity` creates a VLA-like compound literal on the stack —
|
||||
passing a runtime variable triggers undefined behaviour and compiler warnings.
|
||||
Use `wpArrayAllocCapacity` with an arena allocator for runtime sizes.
|
||||
|
||||
Initialise arrays with `WP_ARRAY_INIT_FILLED` to set `count = capacity`
|
||||
immediately, allowing direct indexing.
|
||||
|
||||
## Documentation
|
||||
|
||||
Save research notes and implementation plans as markdown in `documents/`:
|
||||
|
||||
Reference in New Issue
Block a user