|
1 | | - |
2 | 1 | # Array Macros for Dynamic Arrays |
3 | 2 |
|
4 | | -A set of macros for managing dynamic arrays in C. These macros simplify operations like creation, resizing, and memory management. |
5 | | - |
6 | | ---- |
7 | | - |
8 | | -## Declaring the Array Type |
| 3 | +Lightweight macro helpers for dynamic arrays in C with safer edge-case handling and better strict-C portability. |
9 | 4 |
|
10 | | -Before using the macros, you need to declare the array type globally using the `generate_array_type(type)` macro. This should be placed in the global header scope to define the array type structure for the specified type `type`. |
| 5 | +## Declare an array type |
11 | 6 |
|
12 | 7 | ```c |
13 | 8 | generate_array_type(int); |
14 | 9 | ``` |
15 | 10 |
|
16 | | -This declares a dynamic array type for `int`. You can use any valid C type, such as `float`, `double`, or custom structs. |
| 11 | +This creates `Array(int)` and `Slice(int)`. |
17 | 12 |
|
18 | | ---- |
| 13 | +## API safety tiers |
19 | 14 |
|
20 | | -## Macros |
| 15 | +Use checked macros by default. Keep unchecked macros only for compatibility or explicitly performance-focused paths where preconditions are guaranteed. |
21 | 16 |
|
22 | | -### **`array_make(T, size)`** |
23 | | -Creates a dynamic array of type `T` with an initial size. |
| 17 | +## Checked APIs (recommended) |
24 | 18 |
|
25 | | -**Usage:** |
26 | | -```c |
27 | | -Array(int) myArray = array_make(int, 10); |
28 | | -``` |
| 19 | +- `array_make(T, size)`: allocate array with initial capacity (`size` can be `0`). |
| 20 | +- `array_free(arr)`: free array memory. |
| 21 | +- `array_reserve(arr, min_capacity)`: ensure capacity, returns `bool` and may update `arr` after `realloc`. |
| 22 | +- `array_try_push(arr, value)`: append one value, returns `bool`. |
| 23 | +- `array_try_at(arr, idx, out_ptr)`: bounds-checked access, returns `bool`. |
| 24 | +- `array_try_slice_t(T, arr, low, high, out_slice)`: bounds-checked slice creation, returns `bool`. |
| 25 | +- `array_back_ptr(arr)`: pointer to last element or `NULL` when empty. |
| 26 | +- `array_length(arr)`: element count. |
| 27 | +- `array_is_empty(arr)`: true if `count == 0`. |
| 28 | +- `array_length_or0(arr)`: safe length for nullable arrays. |
| 29 | +- `array_is_empty_or_true(arr)`: safe empty check for nullable arrays. |
| 30 | +- `array_start(arr)`: pointer to first element. |
29 | 31 |
|
30 | | -### **`array_free(arr)`** |
31 | | -Frees the memory of the array. |
| 32 | +## Compatibility APIs (unchecked) |
32 | 33 |
|
33 | | -**Usage:** |
34 | | -```c |
35 | | -array_free(myArray); |
36 | | -``` |
| 34 | +These are kept for compatibility and speed-focused code paths: |
37 | 35 |
|
38 | | -### **`array_push(arr, value)`** |
39 | | -Appends a value to the end of the array, resizing if necessary. |
| 36 | +- `array_push(arr, value)`: delegates to `array_try_push` and ignores failure. |
| 37 | +- `array_at(arr, idx)`: unchecked index access. |
| 38 | +- `array_end(arr)`: unchecked last-element pointer (invalid on empty arrays). |
| 39 | +- `array_end_unchecked(arr)`: explicit unchecked alias. |
| 40 | +- `slice_from_array_t(T, arr, low, high)`: unchecked slice creation. |
40 | 41 |
|
41 | | -**Usage:** |
42 | | -```c |
43 | | -array_push(myArray, 42); |
44 | | -``` |
| 42 | +## Portability notes |
45 | 43 |
|
46 | | -### **`array_start(arr)`** |
47 | | -Returns a pointer to the first element of the array. |
| 44 | +- Strict C11/C17 path: use `array_for_each_t(T, arr, it)` and typed slice macros. |
| 45 | +- GNU/Clang convenience path: if `typeof` is supported, `array_for_each(arr, it)` is available. |
48 | 46 |
|
49 | | -**Usage:** |
50 | | -```c |
51 | | -int *start = array_start(myArray); |
52 | | -``` |
53 | | - |
54 | | -### **`array_end(arr)`** |
55 | | -Returns a pointer to the last element of the array. |
| 47 | +## Example (safe usage) |
56 | 48 |
|
57 | | -**Usage:** |
58 | 49 | ```c |
59 | | -int *end = array_end(myArray); |
60 | | -``` |
| 50 | +#include <stdio.h> |
| 51 | +#include "array.h" |
61 | 52 |
|
62 | | -### **`array_at(arr, idx)`** |
63 | | -Accesses the element at a specific index. |
| 53 | +generate_array_type(int); |
64 | 54 |
|
65 | | -**Usage:** |
66 | | -```c |
67 | | -int value = array_at(myArray, 2); |
68 | | -``` |
| 55 | +int main(void) |
| 56 | +{ |
| 57 | + Array(int) values = array_make(int, 0); |
| 58 | + int *at0 = NULL; |
69 | 59 |
|
70 | | -### **`array_length(arr)`** |
71 | | -Returns the number of elements in the array. |
| 60 | + if (!values) return 1; |
| 61 | + if (!array_try_push(values, 10)) return 1; |
| 62 | + if (!array_try_push(values, 20)) return 1; |
72 | 63 |
|
73 | | -**Usage:** |
74 | | -```c |
75 | | -usize length = array_length(myArray); |
76 | | -``` |
| 64 | + if (array_try_at(values, 0, &at0)) |
| 65 | + { |
| 66 | + printf("first=%d\n", *at0); |
| 67 | + } |
77 | 68 |
|
78 | | -### **`array_for_each(arr, el)`** |
79 | | -Iterates over each element in the array. |
| 69 | + array_for_each_t(int, values, it) |
| 70 | + { |
| 71 | + printf("%d\n", *it); |
| 72 | + } |
80 | 73 |
|
81 | | -**Usage:** |
82 | | -```c |
83 | | -array_for_each(myArray, el) |
84 | | -{ |
85 | | - printf("%d\n", *el); |
| 74 | + array_free(values); |
| 75 | + return 0; |
86 | 76 | } |
87 | 77 | ``` |
88 | 78 |
|
89 | | ---- |
| 79 | +## Edge-case behavior |
90 | 80 |
|
91 | | -## Example |
| 81 | +- Zero-capacity arrays grow correctly on first push. |
| 82 | +- Allocation/growth arithmetic is overflow-checked. |
| 83 | +- Reallocation failures do not discard existing array data. |
| 84 | +- `array_try_slice_t` rejects invalid ranges (`low > high` or `high > count`). |
| 85 | +- `array_try_at` and `array_try_slice_t` return `false` when output pointers are `NULL`. |
92 | 86 |
|
93 | | -```c |
94 | | -#include <stdio.h> |
95 | | -#include <stdlib.h> |
| 87 | +## Documentation |
96 | 88 |
|
97 | | -// Assuming macros are included |
| 89 | +Canonical Markdown docs live in `docs/`: |
98 | 90 |
|
99 | | -// Declare the array type globally |
100 | | -generate_array_type(int); |
| 91 | +- [Overview](./docs/overview.md) |
| 92 | +- [Quickstart](./docs/quickstart.md) |
| 93 | +- [API Reference](./docs/api-reference.md) |
| 94 | +- [Examples](./docs/examples.md) |
101 | 95 |
|
102 | | -int main() |
103 | | -{ |
104 | | - Array(int) myArray = array_make(int, 5); // Create array |
| 96 | +## Website (Vite + React + Tailwind) |
105 | 97 |
|
106 | | - array_push(myArray, 10); // Add values |
107 | | - array_push(myArray, 20); |
108 | | - array_push(myArray, 30); |
| 98 | +The project website lives in `site/` and renders the Markdown docs above. |
109 | 99 |
|
110 | | - array_for_each(myArray, el) // Print values |
111 | | - { |
112 | | - printf("%d\n", *el); |
113 | | - } |
| 100 | +Run locally: |
114 | 101 |
|
115 | | - array_free(myArray); // Free memory |
116 | | - return 0; |
117 | | -} |
| 102 | +```sh |
| 103 | +cd site |
| 104 | +npm install |
| 105 | +npm run dev |
118 | 106 | ``` |
119 | 107 |
|
120 | | ---- |
| 108 | +Production build: |
| 109 | + |
| 110 | +```sh |
| 111 | +cd site |
| 112 | +npm run build |
| 113 | +``` |
121 | 114 |
|
122 | | -## Notes |
| 115 | +## GitHub Pages deployment |
123 | 116 |
|
124 | | -- Ensure sufficient memory when resizing arrays. |
125 | | -- Handle memory allocation failures with error handling. |
126 | | -- Always free arrays with `array_free` to prevent memory leaks. |
| 117 | +- Workflow file: `.github/workflows/pages.yml` |
| 118 | +- Trigger: push to `main` (or manual `workflow_dispatch`) |
| 119 | +- Output: `site/dist` uploaded as GitHub Pages artifact |
| 120 | +- Expected URL after deploy: `https://airbus5717.github.io/arraylist/` |
0 commit comments