Update doc formatting

2026-05-10 15:43:19 +01:00
parent 3be9f9424f
commit ec166e2a43
6 changed files with 339 additions and 424 deletions
+105 -164
@@ -2,19 +2,17 @@
The `base` package provides core data structures and memory abstractions: dynamic arrays, doubly-linked lists, queues, strings, and a pluggable allocator interface. The `base` package provides core data structures and memory abstractions: dynamic arrays, doubly-linked lists, queues, strings, and a pluggable allocator interface.
```c
#include "wapp_base.h"
```
**Dependencies:** common **Dependencies:** common
--- ---
## Allocator Interface ## Allocator Interface
A pluggable allocator interface that abstracts memory allocation strategies. A pluggable allocator that abstracts memory allocation strategies. See os package for the arena-backed implementation.
```c
#include "wapp_base.h"
```
### Allocator Struct
```c ```c
typedef struct Allocator Allocator; typedef struct Allocator Allocator;
@@ -33,22 +31,16 @@ struct Allocator {
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_mem_allocator_alloc(allocator, size)` | Allocates memory | | `wapp_mem_allocator_alloc(allocator, size)` | Allocates memory |
| `wapp_mem_allocator_alloc_aligned(allocator, size, alignment)` | Allocated aligned memory | | `wapp_mem_allocator_alloc_aligned(allocator, size, alignment)` | Allocates aligned memory |
| `wapp_mem_allocator_realloc(allocator, ptr, old_size, new_size)` | Reallocates memory | | `wapp_mem_allocator_realloc(allocator, ptr, old_size, new_size)` | Reallocates memory |
| `wapp_mem_allocator_realloc_aligned(allocator, ptr, old_size, new_size, alignment)` | Reallocates aligned memory | | `wapp_mem_allocator_realloc_aligned(allocator, ptr, old_size, new_size, alignment)` | Reallocates aligned memory |
| `wapp_mem_allocator_free(allocator, ptr, size)` | Frees memory | | `wapp_mem_allocator_free(allocator, ptr, size)` | Frees memory |
| `wapp_mem_allocator_invalid(allocator)` | Checks if an allocator is zero-initialised (invalid) | | `wapp_mem_allocator_invalid(allocator)` | Checks whether an allocator is zero-initialised |
The `Allocator` struct holds function pointers and a context object. This allows different allocation strategies (malloc, arena, custom) to share the same interface.
--- ---
## Memory Utilities ## Memory Utilities
```c
#include "wapp_base.h"
```
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_mem_util_align_forward(ptr, alignment)` | Aligns a pointer forward to the given alignment | | `wapp_mem_util_align_forward(ptr, alignment)` | Aligns a pointer forward to the given alignment |
@@ -57,82 +49,69 @@ The `Allocator` struct holds function pointers and a context object. This allows
## Array ## Array
A type-generic dynamic array with stack-allocated and allocator-backed variants. A type-generic dynamic array with both stack-allocated and allocator-backed variants.
```c
#include "wapp_base.h"
```
### Typedefs ### Typedefs
Convenience typedefs for common element types: `GenericArray`, `VoidPtrArray`, `C8Array`, `C16Array`, `C32Array`, `U8Array`, `U16Array`, `U32Array`, `U64Array`, `B8Array`, `I8Array`, `I16Array`, `I32Array`, `I64Array`, `F32Array`, `F64Array`, `F128Array`, `UptrArray`, `IptrArray`, `Str8Array`
`VoidPtrArray`, `C8Array`, `C16Array`, `C32Array`, `U8Array`, `U16Array`, `U32Array`, `U64Array`, `B8Array`, `I8Array`, `I16Array`, `I32Array`, `I64Array`, `F32Array`, `F64Array`, `F128Array`, `UptrArray`, `IptrArray`, `Str8Array`
### Creation ### Creation
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_array(TYPE, ...)` | Creates a stack-allocated array with initial elements. Capacity rounds up to the next power of 2, with a minimum of 2x the element count. | | `wapp_array(type, ...)` | Stack-allocated array with initial elements. Capacity rounds up to the next power of 2. |
| `wapp_array_with_capacity(TYPE, CAPACITY, FLAGS)` | Creates a stack-allocated array with a specific capacity. `FLAGS` is a bitmask of `ArrayInitFlags`. | | `wapp_array_with_capacity(type, capacity, flags)` | Stack-allocated array with a specific capacity. Use `ARRAY_INIT_NONE` or `ARRAY_INIT_FILLED`. |
| `wapp_array_alloc_capacity(TYPE, ALLOCATOR, CAPACITY, FLAGS)` | Creates an allocator-backed array with a specific capacity | | `wapp_array_alloc_capacity(type, allocator, capacity, flags)` | Allocator-backed array with a specific capacity |
### Element Operations ### Element Access & Mutation
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_array_count(ARRAY)` | Returns the current element count | | `wapp_array_count(array)` | Current element count |
| `wapp_array_capacity(ARRAY)` | Returns the total capacity | | `wapp_array_capacity(array)` | Total capacity |
| `wapp_array_item_size(ARRAY)` | Returns the size of a single element | | `wapp_array_item_size(array)` | Size of a single element |
| `wapp_array_set_count(ARRAY, COUNT)` | Sets the element count | | `wapp_array_set_count(array, count)` | Sets the element count |
| `wapp_array_get(TYPE, ARRAY, INDEX)` | Returns a pointer to the element at `INDEX` | | `wapp_array_get(type, array, index)` | Returns pointer to element at `index` |
| `wapp_array_set(TYPE, ARRAY, INDEX, VALUE_PTR)` | Sets the element at `INDEX` from `VALUE_PTR` | | `wapp_array_set(type, array, index, value_ptr)` | Sets element at `index` from `value_ptr` |
| `wapp_array_pop(TYPE, ARRAY)` | Pops and returns the last element by value. Returns `0`/`{}` if empty. | | `wapp_array_pop(type, array)` | Pops and returns the last element by value (or `0`) |
### Mutation (Capped - no allocation) ### Capped Operations (no allocation)
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_array_append_capped(TYPE, ARRAY, VALUE_PTR)` | Appends an element within current capacity. Does not grow. | | `wapp_array_append_capped(type, array, value_ptr)` | Appends within current capacity |
| `wapp_array_extend_capped(TYPE, DST, SRC)` | Extends `DST` with elements from `SRC` within capacity. | | `wapp_array_extend_capped(type, dst, src)` | Extends `dst` with elements from `src` |
| `wapp_array_copy_capped(TYPE, DST, SRC)` | Copies `SRC` elements into `DST` within capacity. | | `wapp_array_copy_capped(type, dst, src)` | Copies `src` into `dst` |
| `wapp_array_clear(TYPE, ARRAY)` | Resets the element count to 0 | | `wapp_array_clear(type, array)` | Resets count to zero |
### Mutation (Allocator-backed - may reallocate) ### Allocator-backed Operations (may grow)
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_array_append_alloc(TYPE, ALLOCATOR, ARRAY, VALUE_PTR, FLAGS)` | Appends, growing via allocator if needed | | `wapp_array_append_alloc(type, allocator, array, value_ptr, flags)` | Appends, growing via allocator |
| `wapp_array_extend_alloc(TYPE, ALLOCATOR, DST, SRC, FLAGS)` | Extends, growing via allocator if needed | | `wapp_array_extend_alloc(type, allocator, dst, src, flags)` | Extends, growing via allocator |
| `wapp_array_copy_alloc(TYPE, ALLOCATOR, DST, SRC, FLAGS)` | Copies, growing via allocator if needed | | `wapp_array_copy_alloc(type, allocator, dst, src, flags)` | Copies, growing via allocator |
### Other ### Other
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_array_calc_alloc_size(TYPE, CAPACITY)` | Calculates the allocation size needed for a given capacity | | `wapp_array_calc_alloc_size(type, capacity)` | Allocation size needed for a given capacity |
| `wapp_array_from_preallcated_buffer(TYPE, BUFFER, BUFFER_SIZE)` | Creates an array from a pre-allocated buffer | | `wapp_array_from_preallcated_buffer(type, buffer, buffer_size)` | Creates an array from a pre-allocated buffer |
### Initialization Flags
| Flag | Description |
|------|-------------|
| `ARRAY_INIT_NONE` | No initialization (elements contain garbage) |
| `ARRAY_INIT_FILLED` | Zero-fill all elements on creation |
### Example ### Example
```c ```c
// Stack-allocated array with initial values // Stack-allocated array
I32Array arr = wapp_array(i32, 10, 20, 30); I32Array arr = wapp_array(i32, 10, 20, 30);
wapp_array_count(&arr); // 3 wapp_array_count(arr); // 3
wapp_array_capacity(&arr); // 8 (next power of 2) wapp_array_capacity(arr); // 8
// Append (capped) // Append (capped)
i32 val = 40; i32 val = 40;
wapp_array_append_capped(i32, &arr, &val); wapp_array_append_capped(i32, arr, &val);
// Heap-allocated array with automatic growth via arena // Allocator-backed with automatic growth
Allocator arena = wapp_mem_arena_allocator_init(KiB(16)); Allocator arena = wapp_mem_arena_allocator_init(KiB(16));
I32Array dyn = wapp_array_alloc_capacity(i32, &arena, 4, ARRAY_INIT_NONE); I32Array dyn = wapp_array_alloc_capacity(i32, &arena, 4, ARRAY_INIT_NONE);
wapp_array_append_alloc(i32, &arena, &dyn, &val, ARRAY_INIT_NONE); wapp_array_append_alloc(i32, &arena, &dyn, &val, ARRAY_INIT_NONE);
@@ -142,73 +121,52 @@ wapp_array_append_alloc(i32, &arena, &dyn, &val, ARRAY_INIT_NONE);
## Doubly-Linked List ## Doubly-Linked List
A type-generic doubly-linked list with both stack-allocated (persistent) and allocator-backed nodes. A type-generic doubly-linked list with node-level operations.
```c
#include "wapp_base.h"
```
### Typedefs ### Typedefs
Convenience typedefs for common element types, both for lists and nodes: `GenericList`, `GenericNode`, `VoidPtrList`, `U8List`, `U16List`, `U32List`, `U64List`, `B8List`, `I8List`, `I16List`, `I32List`, `I64List`, `F32List`, `F64List`, `F128List`, `UptrList`, `IptrList`, `Str8List` (and corresponding `*Node` types).
`VoidPtrList`, `C8List`, `C16List`, `C32List`, `U8List`, `U16List`, `U32List`, `U64List`, `B8List`, `I8List`, `I16List`, `I32List`, `I64List`, `F32List`, `F64List`, `F128List`, `UptrList`, `IptrList`, `Str8List`
### Creation ### Creation
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_dbl_list(TYPE)` | Creates an empty stack-allocated doubly-linked list | | `wapp_dbl_list(type)` | Creates an empty stack-allocated list |
| `wapp_dbl_list_alloc(TYPE, ALLOCATOR)` | Allocates a list using the given allocator | | `wapp_dbl_list_alloc(type, allocator)` | Allocates a list via allocator |
### Element Access ### Element Access
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_dbl_list_get(TYPE, LIST, INDEX)` | Returns a pointer to the element at `INDEX` (walks from nearest end) | | `wapp_dbl_list_get(type, list, index)` | Returns pointer to element at `index` |
| `wapp_dbl_list_get_node(TYPE, LIST, INDEX)` | Returns the `GenericNode*` at `INDEX` | | `wapp_dbl_list_get_node(type, list, index)` | Returns the `GenericNode*` at `index` |
| `wapp_dbl_list_get_node_item(TYPE, NODE)` | Returns a pointer to the item in a node | | `wapp_dbl_list_get_node_item(type, node)` | Returns pointer to the item in a node |
### Mutation (Stack-allocated persistent nodes) ### Mutation
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_dbl_list_push_front(TYPE, LIST, ITEM_PTR)` | Inserts at the front | | `wapp_dbl_list_push_front(type, list, item_ptr)` | Inserts at the front |
| `wapp_dbl_list_push_back(TYPE, LIST, ITEM_PTR)` | Appends at the back | | `wapp_dbl_list_push_back(type, list, item_ptr)` | Appends at the back |
| `wapp_dbl_list_insert(TYPE, LIST, ITEM_PTR, INDEX)` | Inserts at `INDEX` | | `wapp_dbl_list_insert(type, list, item_ptr, index)` | Inserts at `index` |
| `wapp_dbl_list_pop_front(TYPE, LIST)` | Removes and returns the front element (or `NULL`) | | `wapp_dbl_list_pop_front(type, list)` | Removes and returns the front element |
| `wapp_dbl_list_pop_back(TYPE, LIST)` | Removes and returns the back element (or `NULL`) | | `wapp_dbl_list_pop_back(type, list)` | Removes and returns the back element |
| `wapp_dbl_list_remove(TYPE, LIST, INDEX)` | Removes and returns the element at `INDEX` (or `NULL`) | | `wapp_dbl_list_remove(type, list, index)` | Removes and returns element at `index` |
| `wapp_dbl_list_empty(TYPE, LIST)` | Removes all elements from the list | | `wapp_dbl_list_empty(type, list)` | Removes all elements |
### Mutation (Allocator-backed nodes) Allocation-backed variants (`_push_front_alloc`, `_push_back_alloc`, `_insert_alloc`) accept an `allocator` parameter for node allocation. Node-level variants (`_pop_front_node`, `_pop_back_node`, `_remove_node`) return the `GenericNode*` directly.
| Macro | Description |
|-------|-------------|
| `wapp_dbl_list_push_front_alloc(TYPE, ALLOCATOR, LIST, ITEM_PTR)` | Inserts at front with allocated node |
| `wapp_dbl_list_push_back_alloc(TYPE, ALLOCATOR, LIST, ITEM_PTR)` | Appends at back with allocated node |
| `wapp_dbl_list_insert_alloc(TYPE, ALLOCATOR, LIST, ITEM_PTR, INDEX)` | Inserts at `INDEX` with allocated node |
### Node-Level Operations
| Macro | Description |
|-------|-------------|
| `wapp_dbl_list_pop_front_node(TYPE, LIST)` | Removes and returns the front `GenericNode*` (or `NULL`) |
| `wapp_dbl_list_pop_back_node(TYPE, LIST)` | Removes and returns the back `GenericNode*` (or `NULL`) |
| `wapp_dbl_list_remove_node(TYPE, LIST, INDEX)` | Removes and returns the `GenericNode*` at `INDEX` (or `NULL`) |
### Example ### Example
```c ```c
Str8List list = wapp_dbl_list(Str8); Str8List list = wapp_dbl_list(Str8);
Str8 s1 = wapp_str8_lit("hello"); Str8 s1 = wapp_str8_lit("hello");
Str8 s2 = wapp_str8_lit("world"); Str8 s2 = wapp_str8_lit("world");
wapp_dbl_list_push_back(Str8, &list, &s1); wapp_dbl_list_push_back(Str8, &list, &s1);
wapp_dbl_list_push_back(Str8, &list, &s2); wapp_dbl_list_push_back(Str8, &list, &s2);
Str8 *item = wapp_dbl_list_get(Str8, &list, 0); // pointer to s1 Str8 *item = wapp_dbl_list_get(Str8, &list, 0);
``` ```
--- ---
@@ -217,51 +175,41 @@ Str8 *item = wapp_dbl_list_get(Str8, &list, 0); // pointer to s1
A type-generic circular queue (FIFO) backed by a dynamic array. A type-generic circular queue (FIFO) backed by a dynamic array.
```c
#include "wapp_base.h"
```
### Typedefs ### Typedefs
Convenience typedefs: `VoidPtrQueue`, `C8Queue`, `C16Queue`, `C32Queue`, `U8Queue`, `U16Queue`, `U32Queue`, `U64Queue`, `B8Queue`, `I8Queue`, `I32Queue`, `I64Queue`, `F32Queue`, `F64Queue`, `F128Queue`, `UptrQueue`, `IptrQueue`, `Str8Queue` `GenericQueue`, `VoidPtrQueue`, `U8Queue`, `U16Queue`, `U32Queue`, `U64Queue`, `I8Queue`, `I16Queue`, `I32Queue`, `I64Queue`, `F32Queue`, `F64Queue`, `F128Queue`, `UptrQueue`, `IptrQueue`, `Str8Queue`
### Creation ### Creation
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_queue(TYPE, CAPACITY)` | Creates a stack-allocated queue with the given capacity | | `wapp_queue(type, capacity)` | Stack-allocated queue |
| `wapp_queue_alloc(TYPE, ALLOCATOR, CAPACITY)` | Creates an allocator-backed queue | | `wapp_queue_alloc(type, allocator, capacity)` | Allocator-backed queue |
### Operations ### Operations
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_queue_push(TYPE, QUEUE, VALUE_PTR)` | Pushes an item to the back. Fails if full. | | `wapp_queue_push(type, queue, value_ptr)` | Pushes to the back (fails if full) |
| `wapp_queue_push_alloc(TYPE, ALLOCATOR, QUEUE, VALUE_PTR)` | Pushes, growing the backing array via allocator if full | | `wapp_queue_push_alloc(type, allocator, queue, value_ptr)` | Pushes, growing via allocator |
| `wapp_queue_pop(TYPE, QUEUE)` | Pops and returns a pointer to the front item | | `wapp_queue_pop(type, queue)` | Pops and returns pointer to the front item |
| `wapp_queue_capacity(QUEUE)` | Returns the current capacity | | `wapp_queue_capacity(queue)` | Current capacity |
| `wapp_queue_item_size(QUEUE)` | Returns the size of a single element | | `wapp_queue_item_size(queue)` | Size of a single element |
### Example ### Example
```c ```c
I32Queue queue = wapp_queue(i32, 8); I32Queue queue = wapp_queue(i32, 8);
i32 val = 42; i32 val = 42;
wapp_queue_push(i32, &queue, &val); wapp_queue_push(i32, &queue, &val);
i32 *result = wapp_queue_pop(i32, &queue);
i32 *result = wapp_queue_pop(i32, &queue); // pointer to 42
``` ```
--- ---
## Str8 ## Str8
A length-tracked, mutable string type. A length-tracked mutable string type.
```c
#include "wapp_base.h"
```
### Type ### Type
@@ -278,97 +226,90 @@ typedef const Str8 Str8RO; // read-only view
### Printf Helpers ### Printf Helpers
| Macro | Description |
|-------|-------------|
| `WAPP_STR8_SPEC` | Format specifier (`"%.*s"`) for printf |
| `wapp_str8_varg(STRING)` | Expands to `(int)(STRING).size, (STRING).buf` for use with `WAPP_STR8_SPEC` |
```c ```c
#define WAPP_STR8_SPEC "%.*s"
#define wapp_str8_varg(s) (int)((s).size), (s).buf
printf("Value: " WAPP_STR8_SPEC "\n", wapp_str8_varg(my_str)); printf("Value: " WAPP_STR8_SPEC "\n", wapp_str8_varg(my_str));
``` ```
### Creation - Stack ### Creation (Stack)
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_str8_buf(CAPACITY)` | Creates an empty string buffer (zeroed) | | `wapp_str8_buf(capacity)` | Zeroed empty buffer |
| `wapp_str8_lit(STRING)` | Creates a mutable copy of a string literal (capacity = 2x length) | | `wapp_str8_lit(string)` | Mutable copy (capacity = 2x length) |
| `wapp_str8_lit_ro(STRING)` | Creates a read-only view of a string literal | | `wapp_str8_lit_ro(string)` | Read-only view of a string literal |
| `wapp_str8_lit_ro_initialiser_list(STRING)` | For use in static initialisers when compound literals aren't supported | | `wapp_str8_lit_ro_initialiser_list(string)` | For use in static initialisers |
### Creation - Allocator ### Creation (Allocator)
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_str8_alloc_buf(allocator, capacity)` | Allocates an empty string buffer via allocator | | `wapp_str8_alloc_buf(allocator, capacity)` | Empty buffer via allocator |
| `wapp_str8_alloc_and_fill_buf(allocator, capacity)` | Allocates and zero-fills | | `wapp_str8_alloc_and_fill_buf(allocator, capacity)` | Zero-filled buffer |
| `wapp_str8_alloc_cstr(allocator, cstr)` | Copies a C string into an allocated Str8 | | `wapp_str8_alloc_cstr(allocator, cstr)` | Copy a C string |
| `wapp_str8_alloc_str8(allocator, str)` | Copies a Str8 into an allocated Str8 | | `wapp_str8_alloc_str8(allocator, str)` | Copy a Str8 |
| `wapp_str8_alloc_substr(allocator, str, start, end)` | Copies a substring range | | `wapp_str8_alloc_substr(allocator, str, start, end)` | Copy a substring |
| `wapp_str8_alloc_concat(allocator, dst, src)` | Concatenates and returns a new allocated Str8 | | `wapp_str8_alloc_concat(allocator, dst, src)` | Concatenate into new allocation |
| `wapp_str8_dealloc_buf(allocator, str)` | Frees an allocated Str8 | | `wapp_str8_dealloc_buf(allocator, str)` | Free an allocated Str8 |
### Element Access & Mutation ### Access & Mutation
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_str8_get(str, index)` | Gets character at `index`. Returns `'\0'` if out of bounds. | | `wapp_str8_get(str, index)` | Character at `index` (or `'\0'` if out of bounds) |
| `wapp_str8_set(str, index, c)` | Sets character at `index` | | `wapp_str8_set(str, index, c)` | Set character at `index` |
| `wapp_str8_push_back(str, c)` | Appends a single character | | `wapp_str8_push_back(str, c)` | Append a single character |
### Comparison & Search ### Comparison & Search
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_str8_equal(s1, s2)` | Full string equality | | `wapp_str8_equal(s1, s2)` | Full equality |
| `wapp_str8_equal_to_count(s1, s2, count)` | Equality limited to the first `count` characters | | `wapp_str8_equal_to_count(s1, s2, n)` | Equality limited to first `n` characters |
| `wapp_str8_find(str, substr)` | Forward search. Returns index or `-1`. | | `wapp_str8_find(str, substr)` | Forward search (returns index or `-1`) |
| `wapp_str8_rfind(str, substr)` | Reverse search. Returns index or `-1`. | | `wapp_str8_rfind(str, substr)` | Reverse search (returns index or `-1`) |
### Content Manipulation ### Content Manipulation
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_str8_slice(str, start, end)` | Returns a read-only substring view | | `wapp_str8_slice(str, start, end)` | Read-only substring view |
| `wapp_str8_concat_capped(dst, src)` | Concatenates within `dst` capacity | | `wapp_str8_concat_capped(dst, src)` | Concatenate within capacity |
| `wapp_str8_copy_cstr_capped(dst, cstr)` | Copies a C string into a Str8 | | `wapp_str8_copy_cstr_capped(dst, cstr)` | Copy C string into Str8 |
| `wapp_str8_copy_str8_capped(dst, src)` | Copies a Str8 into another Str8 | | `wapp_str8_copy_str8_capped(dst, src)` | Copy Str8 into Str8 |
| `wapp_str8_copy_to_cstr(dst, src, dst_capacity)` | Copies Str8 content to a C string buffer | | `wapp_str8_copy_to_cstr(dst, src, dst_capacity)` | Copy to C string buffer |
| `wapp_str8_format(dst, format, ...)` | printf-style formatting into a Str8 | | `wapp_str8_format(dst, format, ...)` | printf-style formatting |
| `wapp_str8_to_lower(dst, src)` | Converts to lowercase | | `wapp_str8_to_lower(dst, src)` | Convert to lowercase |
| `wapp_str8_to_upper(dst, src)` | Converts to uppercase | | `wapp_str8_to_upper(dst, src)` | Convert to uppercase |
| `wapp_str8_from_bytes(dst, src)` | Converts a `U8Array` of bytes into a Str8 | | `wapp_str8_from_bytes(dst, src)` | Convert `U8Array` bytes to Str8 |
### Split and Join ### Split & Join
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_str8_split(allocator, str, delimiter)` | Splits forward into a `Str8List` (all parts) | | `wapp_str8_split(allocator, str, delimiter)` | Split into `Str8List` |
| `wapp_str8_split_with_max(allocator, str, delimiter, max_splits)` | Splits forward with a maximum number of splits | | `wapp_str8_split_with_max(allocator, str, delimiter, max_splits)` | Split with maximum parts |
| `wapp_str8_rsplit(allocator, str, delimiter)` | Splits in reverse | | `wapp_str8_rsplit(allocator, str, delimiter)` | Reverse split |
| `wapp_str8_rsplit_with_max(allocator, str, delimiter, max_splits)` | Splits in reverse with a maximum | | `wapp_str8_rsplit_with_max(allocator, str, delimiter, max_splits)` | Reverse split with maximum |
| `wapp_str8_join(allocator, list, delimiter)` | Joins a `Str8List` with a delimiter | | `wapp_str8_join(allocator, list, delimiter)` | Join a `Str8List` with delimiter |
| `wapp_str8_list_total_size(list)` | Sum of all string sizes in a list | | `wapp_str8_list_total_size(list)` | Sum of all string sizes in a list |
### Example ### Example
```c ```c
Str8 s = wapp_str8_lit("Hello, World!"); Str8 s = wapp_str8_lit("Hello, World!");
printf(WAPP_STR8_SPEC "\n", wapp_str8_varg(s)); // prints "Hello, World!" printf(WAPP_STR8_SPEC "\n", wapp_str8_varg(s));
Str8 buf = wapp_str8_buf(256);
wapp_str8_copy_cstr_capped(&buf, "Hello");
wapp_str8_push_back(&buf, '!');
// Formatting // Formatting
Str8 buf = wapp_str8_buf(256);
wapp_str8_format(&buf, "Value: %d", 42); wapp_str8_format(&buf, "Value: %d", 42);
// Split // Split and join
Allocator arena = wapp_mem_arena_allocator_init(KiB(16)); Allocator arena = wapp_mem_arena_allocator_init(KiB(16));
Str8 data = wapp_str8_lit("a,b,c"); Str8 data = wapp_str8_lit("a,b,c");
Str8 delim = wapp_str8_lit_ro(","); Str8 delim = wapp_str8_lit_ro(",");
Str8List *parts = wapp_str8_split(&arena, &data, &delim); Str8List *parts = wapp_str8_split(&arena, &data, &delim);
// Join
Str8 *joined = wapp_str8_join(&arena, parts, &delim); Str8 *joined = wapp_str8_join(&arena, parts, &delim);
``` ```
+100 -94
@@ -1,106 +1,109 @@
# common # common
The `common` package provides foundational type definitions, platform detection, assertion macros, and miscellaneous utilities used by all other packages. The `common` package provides foundational type definitions, platform detection, assertion macros, and miscellaneous utilities used across the entire library.
**Dependencies:** None
---
## Aliases
Convenient typedefs for primitive types and qualifiers.
```c ```c
#include "wapp_common.h" #include "wapp_common.h"
``` ```
### Integer Types **Dependencies:** None
| Type | Underlying | ---
|------|-----------|
| `u8`, `u16`, `u32`, `u64` | `uint8_t`, `uint16_t`, `uint32_t`, `uint64_t` |
| `i8`, `i16`, `i32`, `i64` | `int8_t`, `int16_t`, `int32_t`, `int64_t` |
| `b8` | `uint8_t` (boolean) |
| `uptr`, `iptr` | `uintptr_t`, `intptr_t` |
### Character Types ## Type Aliases
| Type | Description | Convenient typedefs for primitive types.
|------|-------------|
| `c8` | UTF-8 code unit (`uint8_t` or `char8_t`) |
| `c16` | UTF-16 code unit (`uint16_t` or `char16_t`) |
| `c32` | UTF-32 code unit (`uint32_t` or `char32_t`) |
### Floating-Point Types ```c
// Integer types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef int8_t i8;
typedef int16_t i16;
typedef int32_t i32;
typedef int64_t i64;
typedef uint8_t b8; // boolean
typedef uintptr_t uptr;
typedef intptr_t iptr;
| Type | Description | // Character types
|------|-------------| typedef uint8_t c8; // UTF-8 code unit
| `f32` | 32-bit float | typedef uint16_t c16; // UTF-16 code unit
| `f64` | 64-bit double | typedef uint32_t c32; // UTF-32 code unit
| `f128` | 80+ bit long double |
// Floating-point types
typedef float f32;
typedef double f64;
typedef long double f128;
```
Where available, `c8`/`c16`/`c32` map to `char8_t`/`char16_t`/`char32_t`.
### Boolean Macros (C only) ### Boolean Macros (C only)
In C, `true` and `false` are defined as `(b8)1` and `(b8)0` respectively when unavailable. In C, `true` and `false` are defined as `(b8)1` and `(b8)0` when not already available.
### Qualifier Macros ### Qualifier Macros
| Macro | Expands To | Description | | Macro | Description |
|-------|-----------|-------------| |-------|-------------|
| `wapp_extern` | `extern` | External linkage | | `wapp_extern` | External linkage (`extern`) |
| `wapp_intern` | `static` | Internal linkage | | `wapp_intern` | Internal linkage (`static`) |
| `wapp_persist` | `static` | Persistent storage duration | | `wapp_persist` | Persistent storage (`static`) |
| `wapp_class_mem` | `static` | Class-level static (C++ only) | | `wapp_class_mem` | Class-level static (C++ only) |
### C/C++ Interop ### C/C++ Interop
```c ```c
BEGIN_C_LINKAGE // extern "C" { (C++ only) BEGIN_C_LINKAGE // extern "C" { (C++ only)
END_C_LINKAGE // } (C++ only) END_C_LINKAGE // } (C++ only)
``` ```
--- ---
## Platform Detection ## Platform Detection
The library auto-detects the target platform and defines the appropriate macros. The library auto-detects the target platform and language version at compile time.
### Platform Macros ```c
#include "wapp_common.h"
```
**OS Family:** ### Operating Systems
- `WAPP_PLATFORM_POSIX` - Any POSIX-compliant system
- `WAPP_PLATFORM_WINDOWS` - Any Windows system (including Cygwin)
- `WAPP_PLATFORM_UNIX` - Traditional Unix systems
**Specific Platforms:** | Macro | Targets |
- `WAPP_PLATFORM_LINUX` - Linux |-------|---------|
- `WAPP_PLATFORM_MACOS` - macOS | `WAPP_PLATFORM_POSIX` | All POSIX-compliant systems |
- `WAPP_PLATFORM_IOS` - iOS | `WAPP_PLATFORM_LINUX` | Linux |
- `WAPP_PLATFORM_ANDROID` - Android | `WAPP_PLATFORM_MACOS` | macOS |
- `WAPP_PLATFORM_FREE_BSD` - FreeBSD | `WAPP_PLATFORM_IOS` | iOS |
- `WAPP_PLATFORM_NET_BSD` - NetBSD | `WAPP_PLATFORM_ANDROID` | Android |
- `WAPP_PLATFORM_OPEN_BSD` - OpenBSD | `WAPP_PLATFORM_FREE_BSD` | FreeBSD |
- `WAPP_PLATFORM_DRAGON_FLY` - DragonFly BSD | `WAPP_PLATFORM_NET_BSD` | NetBSD |
- `WAPP_PLATFORM_GNU` - GNU/Hurd | `WAPP_PLATFORM_OPEN_BSD` | OpenBSD |
- `WAPP_PLATFORM_CYGWIN` - Cygwin | `WAPP_PLATFORM_DRAGON_FLY` | DragonFly BSD |
- `WAPP_PLATFORM_WINDOWS64` - 64-bit Windows | `WAPP_PLATFORM_GNU` | GNU/Hurd |
- `WAPP_PLATFORM_WINDOWS32` - 32-bit Windows | `WAPP_PLATFORM_CYGWIN` | Cygwin |
- `WAPP_PLATFORM_APPLE` - Any Apple platform | `WAPP_PLATFORM_WINDOWS` | All Windows (32-bit, 64-bit, Cygwin) |
| `WAPP_PLATFORM_APPLE` | All Apple platforms |
### Language Version Macros ### Language Version
**C Language:** | Macro | Defined When |
- `WAPP_PLATFORM_C` - Defined when compiling as C |-------|-------------|
- `WAPP_PLATFORM_C89`, `WAPP_PLATFORM_C99`, `WAPP_PLATFORM_C11`, `WAPP_PLATFORM_C17`, `WAPP_PLATFORM_C23` | `WAPP_PLATFORM_C` | Compiling as C |
| `WAPP_PLATFORM_C99`, `WAPP_PLATFORM_C11`, `WAPP_PLATFORM_C17`, `WAPP_PLATFORM_C23` | Specific C standard versions |
**C++ Language:** | `WAPP_PLATFORM_CPP` | Compiling as C++ |
- `WAPP_PLATFORM_CPP` - Defined when compiling as C++ | `WAPP_PLATFORM_CPP11`, `WAPP_PLATFORM_CPP14`, `WAPP_PLATFORM_CPP17`, `WAPP_PLATFORM_CPP20`, `WAPP_PLATFORM_CPP23` | Specific C++ standard versions |
- `WAPP_PLATFORM_CPP98`, `WAPP_PLATFORM_CPP11`, `WAPP_PLATFORM_CPP14`, `WAPP_PLATFORM_CPP17`, `WAPP_PLATFORM_CPP20`, `WAPP_PLATFORM_CPP23`
--- ---
## Assertions ## Assertions
Runtime and compile-time assertion macros with configurable behaviour.
```c ```c
#include "wapp_common.h" #include "wapp_common.h"
``` ```
@@ -109,11 +112,16 @@ The library auto-detects the target platform and defines the appropriate macros.
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_static_assert(EXPR, MSG)` | Compile-time assertion using `extern char` trick | | `wapp_static_assert(expr, msg)` | Compile-time assertion via `extern char` trick |
| `wapp_runtime_assert(EXPR, MSG)` | Runtime assertion (disabled by `WAPP_NO_RUNTIME_ASSERT`) | | `wapp_runtime_assert(expr, msg)` | Runtime check; aborts with file/line/function info on failure |
| `wapp_debug_assert(EXPR, MSG)` | Runtime assertion, only active when `WAPP_DEBUG_ASSERT` is defined | | `wapp_debug_assert(expr, msg)` | Like `wapp_runtime_assert`, but only active when `WAPP_DEBUG_ASSERT` is defined |
On failure, assertions print the file, line, function, expression value, and diagnostic message to `stderr`, then call `abort()`. On failure, the diagnostic includes the file name, line number, function name, expression value, and message:
```
src/foo.c:42 (In function `load_config`): Assertion failed (1)
Diagnostic: config should not be NULL
```
### Build Configuration ### Build Configuration
@@ -121,7 +129,7 @@ On failure, assertions print the file, line, function, expression value, and dia
// Enable debug assertions during development // Enable debug assertions during development
#define WAPP_DEBUG_ASSERT #define WAPP_DEBUG_ASSERT
// Disable all runtime assertions for release // Disable all runtime assertions for release builds
#define WAPP_NO_RUNTIME_ASSERT #define WAPP_NO_RUNTIME_ASSERT
``` ```
@@ -129,6 +137,8 @@ On failure, assertions print the file, line, function, expression value, and dia
## Misc Utilities ## Misc Utilities
Helper macros for size literals, alignment, and bit operations.
```c ```c
#include "wapp_common.h" #include "wapp_common.h"
``` ```
@@ -137,32 +147,28 @@ On failure, assertions print the file, line, function, expression value, and dia
Binary (IEC) prefixes: Binary (IEC) prefixes:
| Macro | Formula | | Macro | Expands To |
|-------|---------| |-------|-----------|
| `KiB(SIZE)` | `SIZE << 10` | | `KiB(n)` | `n << 10` |
| `MiB(SIZE)` | `SIZE << 20` | | `MiB(n)` | `n << 20` |
| `GiB(SIZE)` | `SIZE << 30` | | `GiB(n)` | `n << 30` |
| `TiB(SIZE)` | `SIZE << 40` | | `TiB(n)` | `n << 40` |
| `PiB(SIZE)` | `SIZE << 50` |
| `EiB(SIZE)` | `SIZE << 60` |
Decimal (SI) prefixes: Decimal (SI) prefixes:
| Macro | Formula | | Macro | Expands To |
|-------|---------| |-------|-----------|
| `KB(SIZE)` | `SIZE * 1000` | | `KB(n)` | `n * 1000` |
| `MB(SIZE)` | `KB(SIZE) * 1000` | | `MB(n)` | `KB(n) * 1000` |
| `GB(SIZE)` | `MB(SIZE) * 1000` | | `GB(n)` | `MB(n) * 1000` |
| `TB(SIZE)` | `GB(SIZE) * 1000` | | `TB(n)` | `GB(n) * 1000` |
| `PB(SIZE)` | `TB(SIZE) * 1000` |
| `EB(SIZE)` | `PB(SIZE) * 1000` |
### Utility Macros ### Other Utilities
| Macro | Description | | Macro / Function | Description |
|-------|-------------| |------------------|-------------|
| `wapp_misc_utils_reserve_padding(SIZE)` | Inserts padding bytes to align a struct field to pointer size | | `wapp_misc_utils_reserve_padding(size)` | Inserts padding to align a struct field to pointer size |
| `wapp_misc_utils_u64_round_up_pow2(X)` | Rounds `X` up to the nearest power of 2 | | `wapp_misc_utils_u64_round_up_pow2(x)` | Rounds `x` up to the nearest power of 2 |
| `wapp_is_power_of_two(NUM)` | Checks if `NUM` is a power of 2 | | `wapp_is_power_of_two(n)` | Tests whether `n` is a power of 2 |
| `wapp_pointer_offset(PTR, OFFSET)` | Adds a byte offset to a pointer | | `wapp_pointer_offset(ptr, offset)` | Adds a byte offset to a pointer |
| `wapp_misc_utils_va_args_count(T, ...)` | Returns the number of variadic arguments of type `T` | | `wapp_misc_utils_va_args_count(t, ...)` | Returns the number of variadic arguments of type `t` |
+68 -104
@@ -1,6 +1,10 @@
# os # os
The `os` package provides OS-level abstractions: file I/O, memory-mapped arena allocators, shell command execution, terminal colour output, and path manipulation. The `os` package provides OS-level abstractions: virtual memory, arena allocators, file I/O, shell command execution, terminal colour output, and path manipulation.
```c
#include "wapp_os.h"
```
**Dependencies:** common, base **Dependencies:** common, base
@@ -10,17 +14,13 @@ The `os` package provides OS-level abstractions: file I/O, memory-mapped arena a
Low-level virtual memory allocation. Low-level virtual memory allocation.
```c
#include "wapp_os.h"
```
### Types ### Types
| Type | Description | | Type | Values |
|------|-------------| |------|--------|
| `MemAccess` | Memory access permissions: `WAPP_MEM_ACCESS_NONE`, `WAPP_MEM_ACCESS_READ_ONLY`, `WAPP_MEM_ACCESS_EXEC_ONLY`, `WAPP_MEM_ACCESS_READ_WRITE`, `WAPP_MEM_ACCESS_READ_EXEC`, `WAPP_MEM_ACCESS_READ_WRITE_EXEC` | | `MemAccess` | `WAPP_MEM_ACCESS_NONE`, `WAPP_MEM_ACCESS_READ_ONLY`, `WAPP_MEM_ACCESS_EXEC_ONLY`, `WAPP_MEM_ACCESS_READ_WRITE`, `WAPP_MEM_ACCESS_READ_EXEC`, `WAPP_MEM_ACCESS_READ_WRITE_EXEC` |
| `MemAllocFlags` | Allocation flags: `WAPP_MEM_ALLOC_RESERVE`, `WAPP_MEM_ALLOC_COMMIT` | | `MemAllocFlags` | `WAPP_MEM_ALLOC_RESERVE`, `WAPP_MEM_ALLOC_COMMIT` |
| `MemInitType` | Initialization: `WAPP_MEM_INIT_UNINITIALISED`, `WAPP_MEM_INIT_INITIALISED` | | `MemInitType` | `WAPP_MEM_INIT_UNINITIALISED`, `WAPP_MEM_INIT_INITIALISED` |
### Functions ### Functions
@@ -33,37 +33,35 @@ Low-level virtual memory allocation.
On POSIX, `wapp_os_mem_alloc` wraps `mmap` and `wapp_os_mem_free` wraps `munmap`. On Windows they wrap `VirtualAlloc` and `VirtualFree`. On POSIX, `wapp_os_mem_alloc` wraps `mmap` and `wapp_os_mem_free` wraps `munmap`. On Windows they wrap `VirtualAlloc` and `VirtualFree`.
POSIX uses `MAP_POPULATE` (Linux/GNU) or `MAP_PREFAULT_READ` (FreeBSD) for the commit flag. Other POSIX platforms (BSD, Apple) set both flags to `0`, relying on lazy mapping. The commit flag behaviour varies by platform:
- Linux/GNU: `WAPP_MEM_ALLOC_COMMIT` maps to `MAP_POPULATE`
On Windows, `WAPP_MEM_ALLOC_RESERVE` maps to `MEM_RESERVE` and `WAPP_MEM_ALLOC_COMMIT` maps to `MEM_COMMIT`. - FreeBSD: `WAPP_MEM_ALLOC_COMMIT` maps to `MAP_PREFAULT_READ`
- Other BSD/Apple/Unix: both flags are `0` (lazy mapping)
- Windows: `WAPP_MEM_ALLOC_RESERVE` = `MEM_RESERVE`, `WAPP_MEM_ALLOC_COMMIT` = `MEM_COMMIT`
--- ---
## Arena Allocator ## Arena Allocator
A bump allocator backed by OS virtual memory (or a user-provided buffer). Provides fast, sequential allocations with temporary allocation scoping (memory stacking). A bump allocator backed by OS virtual memory (or a user-provided buffer). Provides fast sequential allocations with temporary scope support.
```c
#include "wapp_os.h"
```
### Initialization ### Initialization
| Function / Macro | Description | | Function / Macro | Description |
|------------------|-------------| |------------------|-------------|
| `wapp_mem_arena_init_allocated(arena, base_capacity)` | Initialises an arena with reserved OS memory | | `wapp_mem_arena_init_allocated(arena, base_capacity)` | Arena backed by reserved OS memory |
| `wapp_mem_arena_init_allocated_commit(arena, base_capacity)` | Reserves and commits OS memory | | `wapp_mem_arena_init_allocated_commit(arena, base_capacity)` | Reserved and committed |
| `wapp_mem_arena_init_allocated_zero(arena, base_capacity)` | Reserves and zeroes OS memory | | `wapp_mem_arena_init_allocated_zero(arena, base_capacity)` | Reserved and zeroed |
| `wapp_mem_arena_init_allocated_commit_and_zero(arena, base_capacity)` | Reserves, commits, and zeroes | | `wapp_mem_arena_init_allocated_commit_and_zero(arena, base_capacity)` | Reserved, committed, and zeroed |
| `wapp_mem_arena_init_allocated_custom(arena, base_capacity, flags, zero)` | Full control over initialization | | `wapp_mem_arena_init_allocated_custom(arena, base_capacity, flags, zero)` | Full control |
| `wapp_mem_arena_init_buffer(arena, buffer, buffer_size)` | Initialises an arena from a pre-existing buffer | | `wapp_mem_arena_init_buffer(arena, buffer, buffer_size)` | Arena from a pre-existing buffer |
### Allocation ### Allocation
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_mem_arena_alloc(arena, size)` | Bump-allocates memory | | `wapp_mem_arena_alloc(arena, size)` | Bump allocates memory |
| `wapp_mem_arena_alloc_aligned(arena, size, alignment)` | Bump-allocates aligned memory | | `wapp_mem_arena_alloc_aligned(arena, size, alignment)` | Bump allocates aligned memory |
| `wapp_mem_arena_realloc(arena, ptr, old_size, new_size)` | Reallocates within the arena | | `wapp_mem_arena_realloc(arena, ptr, old_size, new_size)` | Reallocates within the arena |
| `wapp_mem_arena_realloc_aligned(arena, ptr, old_size, new_size, alignment)` | Reallocates aligned | | `wapp_mem_arena_realloc_aligned(arena, ptr, old_size, new_size, alignment)` | Reallocates aligned |
@@ -71,10 +69,10 @@ A bump allocator backed by OS virtual memory (or a user-provided buffer). Provid
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_mem_arena_temp_begin(arena)` | Saves the current position (start of temp scope) | | `wapp_mem_arena_temp_begin(arena)` | Saves current position |
| `wapp_mem_arena_temp_end(arena)` | Rewinds to the saved position (ends temp scope) | | `wapp_mem_arena_temp_end(arena)` | Rewinds to saved position (ends temporary scope) |
| `wapp_mem_arena_clear(arena)` | Zeroes all arena memory | | `wapp_mem_arena_clear(arena)` | Zeroes all arena memory |
| `wapp_mem_arena_destroy(arena)` | Frees the arena and sets pointer to `NULL` | | `wapp_mem_arena_destroy(arena)` | Frees arena and sets pointer to `NULL` |
### Example ### Example
@@ -84,7 +82,7 @@ wapp_mem_arena_init_allocated(&arena, MiB(1));
i32 *numbers = wapp_mem_arena_alloc(arena, 100 * sizeof(i32)); i32 *numbers = wapp_mem_arena_alloc(arena, 100 * sizeof(i32));
// Temporary scope // Temporary allocation scope
wapp_mem_arena_temp_begin(arena); wapp_mem_arena_temp_begin(arena);
// ... temporary allocations ... // ... temporary allocations ...
wapp_mem_arena_temp_end(arena); // memory rewound wapp_mem_arena_temp_end(arena); // memory rewound
@@ -94,15 +92,11 @@ wapp_mem_arena_destroy(&arena); // arena is now NULL
### Arena-backed Allocator ### Arena-backed Allocator
Wraps an `Arena` in the `Allocator` interface (from base). Wraps an `Arena` in the `Allocator` interface from base.
```c
#include "wapp_os.h"
```
| Function / Macro | Description | | Function / Macro | Description |
|------------------|-------------| |------------------|-------------|
| `wapp_mem_arena_allocator_init(capacity)` | Creates an `Allocator` backed by a new arena | | `wapp_mem_arena_allocator_init(capacity)` | `Allocator` backed by a new arena |
| `wapp_mem_arena_allocator_init_commit(capacity)` | With committed memory | | `wapp_mem_arena_allocator_init_commit(capacity)` | With committed memory |
| `wapp_mem_arena_allocator_init_zero(capacity)` | With zeroed memory | | `wapp_mem_arena_allocator_init_zero(capacity)` | With zeroed memory |
| `wapp_mem_arena_allocator_init_commit_and_zero(capacity)` | With committed and zeroed memory | | `wapp_mem_arena_allocator_init_commit_and_zero(capacity)` | With committed and zeroed memory |
@@ -113,7 +107,7 @@ Wraps an `Arena` in the `Allocator` interface (from base).
| `wapp_mem_arena_allocator_clear(allocator)` | Clear arena | | `wapp_mem_arena_allocator_clear(allocator)` | Clear arena |
| `wapp_mem_arena_allocator_destroy(allocator)` | Destroy arena | | `wapp_mem_arena_allocator_destroy(allocator)` | Destroy arena |
**Note:** The arena allocator only supports `alloc` and `alloc_aligned`. `realloc`, `realloc_aligned`, and `free` are not implemented (individual frees are unsupported by arenas). > **Note:** The arena allocator only supports `alloc` and `alloc_aligned`. `realloc`, `realloc_aligned`, and `free` are not implemented (arenas do not support individual frees).
```c ```c
Allocator allocator = wapp_mem_arena_allocator_init(KiB(16)); Allocator allocator = wapp_mem_arena_allocator_init(KiB(16));
@@ -125,32 +119,28 @@ wapp_mem_arena_allocator_destroy(&allocator);
## File I/O ## File I/O
Cross-platform file operations. Cross-platform file operations with array-level read/write support.
```c
#include "wapp_os.h"
```
### Types ### Types
| Type | Description | | Type | Description |
|------|-------------| |------|-------------|
| `WFile` | Opaque file handle | | `WFile` | Opaque file handle |
| `FileAccessMode` | Access mode enum | | `FileAccessMode` | Access mode (see below) |
| `FileSeekOrigin` | Seek origin enum | | `FileSeekOrigin` | Seek origin |
### File Access Modes ### File Access Modes
| Mode | Description | | Mode | stdio Equivalent | Description |
|------|-------------| |------|-----------------|-------------|
| `WAPP_ACCESS_READ` | Read-only (`r`) | | `WAPP_ACCESS_READ` | `r` | Read-only |
| `WAPP_ACCESS_WRITE` | Write-only, truncates (`w`) | | `WAPP_ACCESS_WRITE` | `w` | Write-only, truncates |
| `WAPP_ACCESS_APPEND` | Append (`a`) | | `WAPP_ACCESS_APPEND` | `a` | Append |
| `WAPP_ACCESS_READ_EX` | Read/write (`r+`) | | `WAPP_ACCESS_READ_EX` | `r+` | Read/write |
| `WAPP_ACCESS_WRITE_EX` | Read/write, truncates (`w+`) | | `WAPP_ACCESS_WRITE_EX` | `w+` | Read/write, truncates |
| `WAPP_ACCESS_APPEND_EX` | Read/append (`a+`) | | `WAPP_ACCESS_APPEND_EX` | `a+` | Read/append |
| `WAPP_ACCESS_WRITE_FAIL_ON_EXIST` | Write, fail if exists (`wx`) | | `WAPP_ACCESS_WRITE_FAIL_ON_EXIST` | `wx` | Write, fail if exists |
| `WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX` | Read/write, fail if exists (`wx+`) | | `WAPP_ACCESS_WRITE_FAIL_ON_EXIST_EX` | `wx+` | Read/write, fail if exists |
### Seek Origins ### Seek Origins
@@ -166,24 +156,20 @@ Cross-platform file operations.
|----------|-------------| |----------|-------------|
| `wapp_file_open(allocator, filepath, mode)` | Opens a file | | `wapp_file_open(allocator, filepath, mode)` | Opens a file |
| `wapp_file_close(file)` | Closes a file | | `wapp_file_close(file)` | Closes a file |
| `wapp_file_read(buffer, file, byte_count)` | Reads raw bytes. Returns bytes read. | | `wapp_file_read(buf, file, byte_count)` | Reads raw bytes. Returns bytes read. |
| `wapp_file_write(buffer, file, byte_count)` | Writes raw bytes. Returns bytes written or negative on error. | | `wapp_file_write(buf, file, byte_count)` | Writes raw bytes. Returns count or negative on error. |
| `wapp_file_read_array(dst_array, file, item_count)` | Reads array elements from file | | `wapp_file_read_array(dst_array, file, item_count)` | Reads array elements from file |
| `wapp_file_write_array(src_array, file, item_count)` | Writes array elements to file | | `wapp_file_write_array(src_array, file, item_count)` | Writes array elements to file |
| `wapp_file_seek(file, offset, origin)` | Seeks to a position. Returns the new position or negative on error. | | `wapp_file_seek(file, offset, origin)` | Seeks to position. Returns new position or negative. |
| `wapp_file_get_current_position(file)` | Returns the current file cursor position or negative on error | | `wapp_file_get_current_position(file)` | Current file cursor position |
| `wapp_file_get_length(file)` | Returns the file size in bytes | | `wapp_file_get_length(file)` | File size in bytes |
| `wapp_file_flush(file)` | Flushes file buffers | | `wapp_file_flush(file)` | Flushes file buffers |
| `wapp_file_rename(old_path, new_path)` | Renames a file | | `wapp_file_rename(old_path, new_path)` | Renames a file |
| `wapp_file_remove(path)` | Deletes a file | | `wapp_file_remove(path)` | Deletes a file |
### Platform Notes ### Platform Notes
On POSIX, `WFile` stores an `i32 fd` (file descriptor) and all operations wrap POSIX system calls (`open`, `read`, `write`, `lseek`, `ftruncate`, `close`, `rename`, `unlink`). On POSIX, `WFile` wraps an `i32 fd` and operations use POSIX system calls (`open`, `read`, `write`, `lseek`, `close`, `rename`, `unlink`). On Windows, `WFile` wraps a `HANDLE` and operations use Win32 API (`CreateFile`, `ReadFile`, `WriteFile`, `SetFilePointerEx`, `CloseHandle`, `MoveFileEx`, `DeleteFile`).
On Windows, `WFile` stores a `HANDLE` and operations wrap Win32 API calls (`CreateFile`, `ReadFile`, `WriteFile`, `SetFilePointerEx`, `GetFileSizeEx`, `FlushFileBuffers`, `CloseHandle`, `MoveFileEx`, `DeleteFile`).
Newline convention: `END_OF_LINE` is `"\n"` on POSIX and `"\r\n"` on Windows.
### Example ### Example
@@ -198,10 +184,9 @@ I32Array arr = wapp_array_from_preallcated_buffer(i32, data, sizeof(data));
wapp_file_write_array(arr, f, 3); wapp_file_write_array(arr, f, 3);
wapp_file_close(f); wapp_file_close(f);
// Read // Read back
f = wapp_file_open(&arena, &filename, WAPP_ACCESS_READ); f = wapp_file_open(&arena, &filename, WAPP_ACCESS_READ);
i64 len = wapp_file_get_length(f); i64 len = wapp_file_get_length(f);
// ... read into buffer ...
wapp_file_close(f); wapp_file_close(f);
wapp_file_remove(&filename); wapp_file_remove(&filename);
``` ```
@@ -212,10 +197,6 @@ wapp_file_remove(&filename);
Execute shell commands and capture or discard their output. Execute shell commands and capture or discard their output.
```c
#include "wapp_os.h"
```
### Types ### Types
```c ```c
@@ -245,26 +226,23 @@ typedef struct CMDResult {
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_shell_commander_execute(out_handling, out_buf, cmd)` | Executes a command. When `out_handling` is `SHELL_OUTPUT_CAPTURE`, `out_buf` must point to a `Str8` buffer. | | `wapp_shell_commander_execute(out_handling, out_buf, cmd)` | Executes a command. Requires a `Str8` buffer when using `SHELL_OUTPUT_CAPTURE`. |
### Example ### Example
```c ```c
// Build command
Str8List cmd = wapp_dbl_list(Str8); Str8List cmd = wapp_dbl_list(Str8);
Str8 prog = wapp_str8_lit("echo"); Str8 prog = wapp_str8_lit("echo");
Str8 arg = wapp_str8_lit("hello world"); Str8 arg = wapp_str8_lit("hello world");
wapp_dbl_list_push_back(Str8, &cmd, &prog); wapp_dbl_list_push_back(Str8, &cmd, &prog);
wapp_dbl_list_push_back(Str8, &cmd, &arg); wapp_dbl_list_push_back(Str8, &cmd, &arg);
// Execute and discard output // Discard output
CMDResult result = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd); CMDResult r = wapp_shell_commander_execute(SHELL_OUTPUT_DISCARD, NULL, &cmd);
// result.exited == true, result.exit_code == 0
// Execute and capture output // Capture output
Str8 buf = wapp_str8_buf(64); Str8 buf = wapp_str8_buf(64);
result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd); r = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
// buf contains "hello world\n"
``` ```
--- ---
@@ -273,39 +251,27 @@ result = wapp_shell_commander_execute(SHELL_OUTPUT_CAPTURE, &buf, &cmd);
Print coloured text to the terminal. Print coloured text to the terminal.
```c
#include "wapp_os.h"
```
### Colour Values ### Colour Values
| Colour | Description | Available colours: `WAPP_TERM_COLOUR_FG_BLACK`, `WAPP_TERM_COLOUR_FG_RED`, `WAPP_TERM_COLOUR_FG_GREEN`, `WAPP_TERM_COLOUR_FG_BLUE`, `WAPP_TERM_COLOUR_FG_CYAN`, `WAPP_TERM_COLOUR_FG_MAGENTA`, `WAPP_TERM_COLOUR_FG_YELLOW`, `WAPP_TERM_COLOUR_FG_WHITE`, plus bright variants (`WAPP_TERM_COLOUR_FG_BR_*`) and `WAPP_TERM_COLOUR_CLEAR`.
|--------|-------------|
| `WAPP_TERM_COLOUR_FG_BLACK` through `WAPP_TERM_COLOUR_FG_WHITE` | Standard foreground colours |
| `WAPP_TERM_COLOUR_FG_BR_BLACK` through `WAPP_TERM_COLOUR_FG_BR_WHITE` | Bright foreground variants |
| `WAPP_TERM_COLOUR_CLEAR` | Reset to default |
### Functions ### Functions
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_shell_termcolour_print_text(text, colour)` | Prints text in the specified colour | | `wapp_shell_termcolour_print_text(text, colour)` | Prints text in the specified colour |
| `wapp_shell_termcolour_clear_colour()` | Resets terminal colours to default | | `wapp_shell_termcolour_clear_colour()` | Resets to default terminal colours |
--- ---
## CPath ## CPath
Cross-platform path manipulation utilities. Cross-platform path manipulation.
```c
#include "wapp_os.h"
```
### Constants ### Constants
| Constant | Value | | Constant | Description |
|----------|-------| |----------|-------------|
| `WAPP_PATH_SEP` | Platform path separator (`'/'` or `'\\'`) | | `WAPP_PATH_SEP` | Platform path separator (`'/'` or `'\\'`) |
| `WAPP_PATH_MAX` | Maximum path length | | `WAPP_PATH_MAX` | Maximum path length |
@@ -313,16 +279,19 @@ Cross-platform path manipulation utilities.
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_cpath_join_path(dst, parts)` | Joins a `Str8List` of path components into a `Str8`. Returns an error code: `CPATH_JOIN_SUCCESS` (0), `CPATH_JOIN_INVALID_ARGS`, `CPATH_JOIN_EMPTY_PARTS`, `CPATH_JOIN_INSUFFICIENT_DST_CAPACITY`. Handles separator insertion automatically. | | `wapp_cpath_join_path(dst, parts)` | Joins a `Str8List` of path components into a `Str8`. Returns `CPATH_JOIN_SUCCESS` (0) or an error code. Handles separator insertion automatically. |
| `wapp_cpath_dirname(allocator, path)` | Returns the parent directory (equivalent to `dirup(path, 1)`) | | `wapp_cpath_dirname(allocator, path)` | Returns the parent directory |
| `wapp_cpath_dirup(allocator, path, count)` | Returns the directory `count` levels up | | `wapp_cpath_dirup(allocator, path, count)` | Returns the directory `count` levels up |
### Error Codes
`CPATH_JOIN_SUCCESS`, `CPATH_JOIN_INVALID_ARGS`, `CPATH_JOIN_EMPTY_PARTS`, `CPATH_JOIN_INSUFFICIENT_DST_CAPACITY`
### Example ### Example
```c ```c
Allocator arena = wapp_mem_arena_allocator_init(KiB(16)); Allocator arena = wapp_mem_arena_allocator_init(KiB(16));
// Join path components
Str8List parts = wapp_dbl_list(Str8); Str8List parts = wapp_dbl_list(Str8);
Str8 root = wapp_str8_lit("/"); Str8 root = wapp_str8_lit("/");
Str8 home = wapp_str8_lit("home"); Str8 home = wapp_str8_lit("home");
@@ -332,9 +301,8 @@ wapp_dbl_list_push_back(Str8, &parts, &home);
wapp_dbl_list_push_back(Str8, &parts, &user); wapp_dbl_list_push_back(Str8, &parts, &user);
Str8 out = wapp_str8_buf(256); Str8 out = wapp_str8_buf(256);
wapp_cpath_join_path(&out, &parts); // out = "/home/user" wapp_cpath_join_path(&out, &parts); // "/home/user"
// Parent directory
Str8 dir = wapp_str8_lit("/home/user/docs"); Str8 dir = wapp_str8_lit("/home/user/docs");
Str8 *parent = wapp_cpath_dirname(&arena, &dir); // "/home/user" Str8 *parent = wapp_cpath_dirname(&arena, &dir); // "/home/user"
Str8 *grandparent = wapp_cpath_dirup(&arena, &dir, 2); // "/home" Str8 *grandparent = wapp_cpath_dirup(&arena, &dir, 2); // "/home"
@@ -346,10 +314,6 @@ Str8 *grandparent = wapp_cpath_dirup(&arena, &dir, 2); // "/home"
Cross-platform wrappers for `popen`/`pclose`. Cross-platform wrappers for `popen`/`pclose`.
```c
#include "wapp_os.h"
```
| Macro | POSIX | Windows | | Macro | POSIX | Windows |
|-------|-------|---------| |-------|-------|---------|
| `wapp_shell_utils_popen` | `popen` | `_popen` | | `wapp_shell_utils_popen` | `popen` | `_popen` |
+16 -14
@@ -1,6 +1,10 @@
# prng # prng
The `prng` package provides a **Xorshift256** pseudo-random number generator (PRNG). It uses a SplitMix64 seeding strategy initialised from the system clock. The `prng` package provides a **Xorshift256** pseudo-random number generator. It uses a SplitMix64 seeding strategy initialised from the system clock.
```c
#include "wapp_prng.h"
```
**Dependencies:** common **Dependencies:** common
@@ -8,11 +12,7 @@ The `prng` package provides a **Xorshift256** pseudo-random number generator (PR
## Xorshift256 ## Xorshift256
A fast, non-cryptographic PRNG with a 256-bit state. A fast, non-cryptographic PRNG with a 256-bit state. Three variants are available with different trade-offs between speed and statistical quality.
```c
#include "wapp_prng.h"
```
### State ### State
@@ -30,19 +30,21 @@ struct XOR256State {
| Function | Description | | Function | Description |
|----------|-------------| |----------|-------------|
| `wapp_prng_xorshift_init_state()` | Seeds and returns a new `XOR256State`. The OS generator is seeded once globally from the system clock (CLOCK_MONOTONIC_RAW on POSIX, `timespec_get` or `time` otherwise). A SplitMix64 generator then expands this into the 4 x 64-bit state. | | `wapp_prng_xorshift_init_state()` | Seeds a new `XOR256State` from the system clock using SplitMix64 expansion |
| `wapp_prng_xorshift_256(state)` | Standard xorshift256 variant. Returns a `u64`. | | `wapp_prng_xorshift_256(state)` | Standard xorshift256. Fastest variant. |
| `wapp_prng_xorshift_256ss(state)` | xorshift256 with "scrambled" output (`rol64(z * 5, 7) * 9`). Passes BigCrush. | | `wapp_prng_xorshift_256ss(state)` | Scrambled output: `rol64(z * 5, 7) * 9`. Passes BigCrush. |
| `wapp_prng_xorshift_256p(state)` | xorshift256 with "+" output (`w + x`). Passes BigCrush. | | `wapp_prng_xorshift_256p(state)` | Plus output: `w + x`. Passes BigCrush. |
The state is seeded once globally from the system clock (`CLOCK_MONOTONIC_RAW` on POSIX, `timespec_get` or `time` otherwise), then expanded via SplitMix64 into four 64-bit state words.
### Example ### Example
```c ```c
XOR256State state = wapp_prng_xorshift_init_state(); XOR256State state = wapp_prng_xorshift_init_state();
u64 r1 = wapp_prng_xorshift_256(&state); u64 r1 = wapp_prng_xorshift_256(&state); // fast
u64 r2 = wapp_prng_xorshift_256ss(&state); u64 r2 = wapp_prng_xorshift_256ss(&state); // high quality (BigCrush)
u64 r3 = wapp_prng_xorshift_256p(&state); u64 r3 = wapp_prng_xorshift_256p(&state); // high quality (BigCrush)
``` ```
The state is passed by pointer and mutated on each call. The `_ss` and `_p` variants provide better statistical quality and pass the BigCrush test suite, while the standard `_256` variant is faster but has known weaknesses. > The `_256ss` and `_256p` variants provide better statistical quality and pass the BigCrush test suite. The standard `_256` variant is faster but has known statistical weaknesses.
+16 -22
@@ -1,6 +1,10 @@
# testing # testing
The `testing` package provides a lightweight test runner that uses terminal colours for pass/fail output. The `testing` package provides a lightweight test runner with coloured pass/fail output. It is designed for the library's own test suite but can be used in any C/C++ project.
```c
#include "wapp_testing.h"
```
**Dependencies:** common, os, base **Dependencies:** common, os, base
@@ -8,11 +12,7 @@ The `testing` package provides a lightweight test runner that uses terminal colo
## Tester ## Tester
A simple test framework. Each test is a function that returns a `TestFuncResult`. Tests are registered by passing their function pointers to `wapp_tester_run_tests`. Each test is a function that returns a `TestFuncResult`. Tests are registered by passing their function pointers to `wapp_tester_run_tests`.
```c
#include "wapp_testing.h"
```
### Types ### Types
@@ -23,29 +23,22 @@ struct TestFuncResult {
b8 passed; b8 passed;
}; };
// Test function signature:
typedef TestFuncResult(TestFunc)(void); typedef TestFuncResult(TestFunc)(void);
``` ```
### Test Result Helper ### Macros
| Macro | Description | | Macro | Description |
|-------|-------------| |-------|-------------|
| `wapp_tester_result(PASSED)` | Creates a `TestFuncResult` with the current function's name via `__func__` | | `wapp_tester_result(passed)` | Creates a `TestFuncResult` using `__func__` as the test name |
| `wapp_tester_run_tests(...)` | Runs all listed test functions (NULL-terminated automatically) |
### Test Runner
| Macro / Function | Description |
|------------------|-------------|
| `wapp_tester_run_tests(func1, func2, ..., funcN)` | Runs all listed test functions. Must be NULL-terminated (the varargs macro automatically appends `NULL`). |
| `run_tests(func1, ...)` | Underlying function (varargs, NULL-terminated) |
### Behaviour ### Behaviour
- Each test runs sequentially in declaration order. - Tests run sequentially in declaration order.
- Passing tests are shown in green (`[PASSED]`), failing tests in red (`[FAILED]`). - Passing tests are shown in green (`[PASSED]`), failing tests in red (`[FAILED]`).
- Output uses terminal colours via `wapp_shell_termcolour_print_text`.
- On the first failure, the runner calls `exit(EXIT_FAILURE)` immediately. - On the first failure, the runner calls `exit(EXIT_FAILURE)` immediately.
- Output uses terminal colours via the os package's `wapp_shell_termcolour_print_text`.
### Example ### Example
@@ -72,6 +65,7 @@ int main(void) {
``` ```
Output: Output:
``` ```
[PASSED] test_addition [PASSED] test_addition
[PASSED] test_subtraction [PASSED] test_subtraction
@@ -80,8 +74,8 @@ Output:
### Writing Tests ### Writing Tests
Each test function must: Each test function must:
1. Have the signature `TestFuncResult test_name(void)` - Have the signature `TestFuncResult test_name(void)`
2. Return `wapp_tester_result(condition)` where `condition` is `true` for pass, `false` for fail - Return `wapp_tester_result(condition)` where `condition` is `true` for pass, `false` for fail
3. Not take any parameters - Take no parameters
Tests that share state (e.g. a file handle or an arena) can use `wapp_intern` (file-level `static`) variables to persist state across sequentially run tests. Tests that share state (e.g. a file handle or arena) can use `wapp_persist` (file-level `static`) variables to persist state across sequentially run tests.
+34 -26
@@ -2,67 +2,75 @@
The `uuid` package provides **UUID v4** generation as specified by RFC 4122. UUIDs are generated using the library's Xorshift256 PRNG and formatted as 36-character strings. The `uuid` package provides **UUID v4** generation as specified by RFC 4122. UUIDs are generated using the library's Xorshift256 PRNG and formatted as 36-character strings.
```c
#include "wapp_uuid.h"
```
**Dependencies:** common, base, prng **Dependencies:** common, base, prng
--- ---
## UUID v4 ## UUID v4
```c
#include "wapp_uuid.h"
```
### Type ### Type
```c ```c
typedef struct WUUID WUUID; typedef struct WUUID WUUID;
struct WUUID { struct WUUID {
Str8 uuid; // The UUID string representation Str8 uuid; // The UUID string representation
}; };
``` ```
### Constants ### Constants
| Constant | Description | | Constant | Value |
|----------|-------------| |----------|-------|
| `UUID_BUF_LENGTH` | `48` - recommended buffer size for UUID strings | | `UUID_BUF_LENGTH` | `48` |
| `WAPP_UUID_SPEC` | `WAPP_STR8_SPEC` - for printf formatting | | `WAPP_UUID_SPEC` | `WAPP_STR8_SPEC` |
| `wapp_uuid_varg(wuuid)` | Expands to `wapp_str8_varg((WUUID).uuid)` for printf |
### Convenience Macro ### Printf Helpers
| Macro | Description | ```c
|-------|-------------| #define wapp_uuid_varg(wuuid) wapp_str8_varg((WUUID).uuid)
| `wapp_uuid_gen_uuid4()` | One-shot UUID v4 generation. Creates a buffer and returns a fully initialised `WUUID` in a single expression - no variables needed. |
printf(WAPP_UUID_SPEC "\n", wapp_uuid_varg(u));
```
### One-shot Generation
```c
WUUID u = wapp_uuid_gen_uuid4();
```
Creates a buffer and returns a fully initialised `WUUID` in a single expression.
### Low-Level API ### Low-Level API
| Function | Description | | Function / Macro | Description |
|----------|-------------| |------------------|-------------|
| `wapp_uuid_create()` | Creates an empty `WUUID` with a zeroed buffer of `UUID_BUF_LENGTH` capacity | | `wapp_uuid_create()` | Creates an empty `WUUID` with a zeroed buffer |
| `wapp_uuid_init_uuid4(uuid)` | Fills a `WUUID` with a randomly generated UUID v4. Returns the same pointer for chaining. | | `wapp_uuid_init_uuid4(uuid)` | Fills a `WUUID` with a randomly generated UUID v4. Returns the same pointer. |
### Example ### Example
```c ```c
// One-shot generation (most common usage) // One-shot
WUUID uuid = wapp_uuid_gen_uuid4(); WUUID uuid = wapp_uuid_gen_uuid4();
printf(WAPP_UUID_SPEC "\n", wapp_uuid_varg(uuid)); printf(WAPP_UUID_SPEC "\n", wapp_uuid_varg(uuid));
// Example output: "f47ac10b-58cc-4372-a567-0e02b2c3d479"
// Two-step (low-level) // Two-step
WUUID u = wapp_uuid_create(); WUUID u = wapp_uuid_create();
wapp_uuid_init_uuid4(&u); wapp_uuid_init_uuid4(&u);
printf(WAPP_UUID_SPEC "\n", wapp_uuid_varg(u));
``` ```
### UUID Format ### UUID Format
The generated UUID follows RFC 4122: Generated UUIDs follow RFC 4122:
``` ```
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
``` ```
Where:
- The `4` identifies version 4 (random) - The `4` identifies version 4 (random)
- `y` is one of `8`, `9`, `a`, or `b` (the variant field) - `y` is one of `8`, `9`, `a`, or `b` (the RFC 4122 variant field)
- All other digits are randomly generated via `wapp_prng_xorshift_256` - All other hex digits are generated via `wapp_prng_xorshift_256`