|
14 | 14 | </div> |
15 | 15 | <p style="margin-top: 10px; margin-bottom: 0;"> |
16 | 16 | <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="License: MIT"></a> |
| 17 | + <a href="https://github.com/EasyMem/easy_stack/blob/main/easy_stack.h"><img src="https://img.shields.io/github/size/EasyMem/easy_stack/easy_stack.h.svg?color=blue" alt="Header Size"></a> |
17 | 18 | <a href="https://en.wikipedia.org/wiki/C11_(C_standard_revision)"><img src="https://img.shields.io/badge/Standard-C99%20%2F%20C11-blue.svg" alt="Standard"></a> |
18 | 19 | <a href="https://www.codefactor.io/repository/github/easymem/easy_stack"><img src="https://www.codefactor.io/repository/github/easymem/easy_stack/badge" alt="CodeFactor"></a> |
19 | 20 | <a href="https://codecov.io/gh/easymem/easy_stack"><img src="https://codecov.io/gh/easymem/easy_stack/graph/badge.svg" alt="codecov"></a> |
| 21 | + <a href="https://github.com/google/fuzzing"><img src="https://img.shields.io/badge/Fuzzing-libFuzzer-blueviolet.svg" alt="Fuzzed with libFuzzer"></a> |
20 | 22 | <a href="https://github.com/easymem/easy_stack/actions/workflows/ci.yml"><img src="https://github.com/easymem/easy_stack/actions/workflows/ci.yml/badge.svg" alt="CI"></a> |
| 23 | + <a href="https://webassembly.org/"><img src="https://img.shields.io/badge/WebAssembly-wasm32%20%2F%20wasm64-blue?logo=webassembly&logoColor=white" alt="WebAssembly"></a> |
| 24 | + <a href="https://registry.platformio.org/libraries/gooderfreed/easy_stack"><img src="https://badges.registry.platformio.org/packages/gooderfreed/library/easy_stack.svg" alt="PlatformIO Registry" /></a> |
| 25 | + <a href="https://www.arduinolibraries.info/libraries/easy_stack"><img src="https://img.shields.io/badge/Arduino-Available-00979D.svg?logo=arduino&logoColor=white" alt="Arduino Available"></a> |
21 | 26 | </p> |
22 | 27 | </td> |
23 | 28 | </tr> |
|
43 | 48 | * **Dynamic Metadata Bit-Width Scaling:** Unlike traditional stack allocators that prefix each allocation with a fixed-size inline header (typically 16 bytes on 64-bit platforms), `easy_stack` dynamically scales metadata cells to 1, 2, 4, or 8 bytes based on overall buffer capacity. For standard frame workloads (< 64 KB), offset cells take only 2 bytes—unlocking up to an **8x reduction in metadata overhead**. |
44 | 49 | * **L1 Cache Line "Free Lunch" Optimization:** The compact `EStack` header requires only 2 machine words (16 bytes on 64-bit systems). By default, on modern desktop and application processors, the library automatically aligns the header boundary to 64-byte or 32-byte cache lines. This guarantees that fetching the stack header into cache automatically and instantly prefetches the **first 24 active metadata offsets** for **free**, bypassing main memory latency entirely. |
45 | 50 | * **XOR-Hardened Stack Markers:** Rollback states (markers) are masked by XORing the current allocation index and signature with the stack's base memory address and `ESTACK_MAGIC`. This catches cross-allocator marker pollution (e.g., passing Stack A's marker to Stack B) and accidental marker corruption with **zero runtime overhead** (1-cycle XOR instructions). |
46 | | -* **Zero-Multiplication Boundary Checks:** Completely eliminates expensive CPU multiplication (`imul`) instructions from the critical allocation path. Since the metadata array cell widths are scaled strictly to powers of two ($1, 2, 4, \text{or } 8$ bytes), calculating the current metadata offset boundary is resolved using an ultra-fast bitwise shift left (`<< meta_type`). This reduces the boundary check to a single addition and shift, executing in just 1-2 CPU cycles. |
| 51 | +* **Zero-Multiplication Boundary Checks:** Completely eliminates expensive CPU multiplication (`imul`) instructions from the critical allocation path. Since the metadata array cell widths are scaled strictly to powers of two (1, 2, 4, or 8 bytes), calculating the current metadata offset boundary is resolved using an ultra-fast bitwise shift left (`<< meta_type`). This reduces the boundary check to a single addition and shift, executing in just 1-2 CPU cycles. |
47 | 52 | * **Arbitrary Power-of-Two Alignment:** Supports customized alignment boundaries (powers of two) for individual allocations, up to the stack's total capacity. Essential for SIMD vectors, cache-line aligned arrays, and hardware DMA buffers. |
48 | 53 | * **Compiler Agnostic & Optimization Resilient:** Verified to work flawlessly across all compiler optimization levels (`-O1` through `-O3`, `-Os`, `-Oz`, `/O1`, `/O2`, `/Ox`). Built with strict adherence to **Strict Aliasing** rules, ensuring that aggressive compiler optimizations never break internal layout mechanics. |
49 | 54 | * **Minimal Header Footprint:** The `EStack` header is extremely compact, consuming exactly 2 machine words (16 bytes on 64-bit systems, 8 bytes on 32-bit systems) to store overall capacity, dynamic metadata bit-width, allocation index, and the dynamic allocation flag. If `ESTACK_NO_ALIGN_HEADER` is defined (which is forced automatically on 8/16-bit platforms), the header alignment padding is completely eliminated to maximize usable space. |
50 | 55 | * **Concurrency Model:** Intentionally lock-free and single-threaded to avoid mutex overhead. Designed for **Thread-Local Storage (TLS)** patterns (one `EStack` instance per thread). |
51 | 56 | * **Embedded and Bare-Metal Ready:** Zero dependencies on standard `libc` heap managers. Can compile on bare-metal architectures with zero feature degradation (`ESTACK_NO_MALLOC`). |
52 | 57 | * **Full C++ Compatibility:** Wrapped in `extern "C"` for seamless integration into both C and C++ codebases. |
| 58 | +* **WebAssembly & Emscripten Optimized:** Fully compliant with 32-bit and 64-bit WebAssembly environments (`wasm32-wasi` and `wasm64-wasi` via Emscripten / WASI). The dynamic metadata scaling is extremely beneficial for web-based engines, minimizing the linear memory footprint of the compiled modules. |
53 | 59 |
|
54 | 60 | --- |
55 | 61 |
|
@@ -114,9 +120,9 @@ Traditional stack allocators suffix or prefix each payload with inline metadata |
114 | 120 |
|
115 | 121 | 1. **Decoupled Alignment:** Payloads are aligned backward at the end of the buffer. Metadata remains packed as a dense array of unaligned, scaled integers at the beginning of the buffer. Because metadata and payloads never sit inline next to each other, **no alignment padding is ever wasted in the control zone**. |
116 | 122 | 2. **Dynamic Scaling:** |
117 | | - * If capacity $\le$ 255 bytes: Offsets are stored as 1-byte `uint8_t` values. |
118 | | - * If capacity $\le$ 65535 bytes: Offsets are stored as 2-byte `uint16_t` values. |
119 | | - * If capacity $\le$ 4 GB: Offsets are stored as 4-byte `uint32_t` values. |
| 123 | + * If capacity ≤ 255 bytes: Offsets are stored as 1-byte `uint8_t` values. |
| 124 | + * If capacity ≤ 65535 bytes: Offsets are stored as 2-byte `uint16_t` values. |
| 125 | + * If capacity ≤ 4 GB: Offsets are stored as 4-byte `uint32_t` values. |
120 | 126 | * Larger capacities scale to 8-byte `uint64_t` values. |
121 | 127 | 3. **Collision Detection:** The allocation cursor checks if the aligned payload address is less than the end of the metadata array (`aligned_ptr < meta_end`). If true, a Stack Overflow is safely caught. |
122 | 128 |
|
@@ -218,6 +224,43 @@ Or compile it directly into its own object file: |
218 | 224 | easy_stack.o: easy_stack.h |
219 | 225 | gcc -x c -DEASY_STACK_IMPLEMENTATION -c easy_stack.h -o easy_stack.o |
220 | 226 | ``` |
| 227 | +*Note: For WebAssembly builds, simply substitute `gcc` with `emcc` (use `-m64` to target 64-bit WASM environments).* |
| 228 | + |
| 229 | +### Integration via CMake |
| 230 | + |
| 231 | +You can integrate `easy_stack` into CMake projects using one of the following methods: |
| 232 | + |
| 233 | +#### Option A: Standard Header-Only (`INTERFACE` library) |
| 234 | +The most common approach. You include the header and define the implementation in one of your C source files manually. |
| 235 | + |
| 236 | +```cmake |
| 237 | +add_library(easy_stack INTERFACE) |
| 238 | +target_include_directories(easy_stack INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) |
| 239 | +# Now simply link it: target_link_libraries(your_target PRIVATE easy_stack) |
| 240 | +``` |
| 241 | + |
| 242 | +#### Option B: Precompiled Implementation (`OBJECT` library) |
| 243 | +If you prefer to compile the implementation once and link it everywhere without polluting your source files with `#define EASY_STACK_IMPLEMENTATION`: |
| 244 | + |
| 245 | +```cmake |
| 246 | +add_library(easy_stack OBJECT) |
| 247 | +target_sources(easy_stack PRIVATE easy_stack.h) |
| 248 | +
|
| 249 | +set_source_files_properties(easy_stack.h PROPERTIES |
| 250 | + HEADER_FILE_ONLY FALSE |
| 251 | + LANGUAGE C |
| 252 | + COMPILE_DEFINITIONS "EASY_STACK_IMPLEMENTATION" |
| 253 | +) |
| 254 | +
|
| 255 | +# Force the compiler to treat the .h file as C source code |
| 256 | +if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU") |
| 257 | + set_source_files_properties(easy_stack.h PROPERTIES COMPILE_FLAGS "-x c") |
| 258 | +elseif(MSVC) |
| 259 | + set_source_files_properties(easy_stack.h PROPERTIES COMPILE_FLAGS "/TC") |
| 260 | +endif() |
| 261 | +
|
| 262 | +# Now link the precompiled object: target_link_libraries(your_target PRIVATE easy_stack) |
| 263 | +``` |
221 | 264 |
|
222 | 265 | ### 2. Standard Heap Allocations (Dynamic) |
223 | 266 | Simple, linear LIFO allocations on a dynamically allocated heap. |
@@ -399,15 +442,20 @@ The library is continuously integrated and tested across a matrix of OSs and Arc |
399 | 442 | | GCC (MinGW) | &logo=windows&logoColor=white) | |
400 | 443 | | Clang |  | |
401 | 444 | | MSVC |  | |
| 445 | +| Emscripten |  | |
402 | 446 |
|
403 | 447 | ### By Architecture |
404 | 448 | | Architecture | Endianness | OS / Environment | Status | |
405 | 449 | | :--- | :--- | :--- | :--- | |
406 | 450 | | `x86_64` | Little | Windows / Linux / macOS |  | |
407 | 451 | | `x86_32` | Little | Windows / Linux |  | |
408 | | -| `AArch64` | Little | Windows (Native ARM64) / Linux |  | |
| 452 | +| `AArch64` | Little | macOS (Apple Silicon) / Linux / Windows 11 ARM |  | |
409 | 453 | | `ARMv7` | Little | Linux | %20%7C%20GCC&label=armv7&logo=arm&logoColor=white) | |
410 | 454 | | `s390x` | **Big** | Linux |  | |
| 455 | +| `wasm32` | Little | Web Browser / Node.js (WASI) |  | |
| 456 | +| `wasm64` | Little | Modern Web / Node.js (Memory64) |  | |
| 457 | + |
| 458 | + |
411 | 459 |
|
412 | 460 | ### C Standards Compliance |
413 | 461 | | Standard | Status | |
|
0 commit comments