{"id":47728401,"url":"https://github.com/easymem/easy_memory","last_synced_at":"2026-04-02T21:03:13.323Z","repository":{"id":333228922,"uuid":"1133146678","full_name":"EasyMem/easy_memory","owner":"EasyMem","description":"A strictly typed, platform-agnostic, and safe memory management system for C. Features arbitrary alignment, triple-key LLRB tree, and zero-dependency bare-metal support.","archived":false,"fork":false,"pushed_at":"2026-04-01T04:17:42.000Z","size":1202,"stargazers_count":20,"open_issues_count":0,"forks_count":2,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-01T05:48:00.067Z","etag":null,"topics":["aarch64","alignment","armv7","bare-metal","c","c11","c99","cross-platform","embedded","endianess","esp32","header-only","memory-allocator","memory-management","no-std","portable","pure-c","rp2040","x86-32","x86-64"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/EasyMem.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-01-13T00:21:00.000Z","updated_at":"2026-04-01T03:59:08.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/EasyMem/easy_memory","commit_stats":null,"previous_names":["easymem/easy_memory"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/EasyMem/easy_memory","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyMem%2Feasy_memory","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyMem%2Feasy_memory/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyMem%2Feasy_memory/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyMem%2Feasy_memory/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/EasyMem","download_url":"https://codeload.github.com/EasyMem/easy_memory/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/EasyMem%2Feasy_memory/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31316133,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aarch64","alignment","armv7","bare-metal","c","c11","c99","cross-platform","embedded","endianess","esp32","header-only","memory-allocator","memory-management","no-std","portable","pure-c","rp2040","x86-32","x86-64"],"created_at":"2026-04-02T21:03:11.802Z","updated_at":"2026-04-02T21:03:13.300Z","avatar_url":"https://github.com/EasyMem.png","language":"C","readme":"\u003ctable\u003e\n  \u003ctr\u003e\n    \u003ctd width=\"150\" valign=\"middle\"\u003e\n      \u003cimg src=\".github/assets/logo.jpeg\" width=\"150\" alt=\"easy_memory logo\" /\u003e\n    \u003c/td\u003e\n    \u003ctd valign=\"middle\"\u003e\n      \u003cdiv id=\"user-content-toc\"\u003e\n        \u003cul style=\"list-style: none; padding: 0; margin: 0;\"\u003e\n          \u003csummary\u003e\n            \u003ch1 style=\"margin: 0;\"\u003eHeader-Only Memory Management System\u003c/h1\u003e\n            \u003ch3\u003eComplex inside. Simple outside.\u003c/h3\u003e\n          \u003c/summary\u003e\n        \u003c/ul\u003e\n      \u003c/div\u003e\n      \u003cp style=\"margin-top: 10px; margin-bottom: 0;\"\u003e\n        \u003ca href=\"https://opensource.org/licenses/MIT\"\u003e\u003cimg src=\"https://img.shields.io/badge/License-MIT-yellow.svg\" alt=\"License: MIT\"\u003e\u003c/a\u003e\n        \u003ca href=\"https://en.wikipedia.org/wiki/C11_(C_standard_revision)\"\u003e\u003cimg src=\"https://img.shields.io/badge/Standard-C99%20%2F%20C11-blue.svg\" alt=\"Standard\"\u003e\u003c/a\u003e\n        \u003ca href=\"https://www.codefactor.io/repository/github/easymem/easy_memory\"\u003e\u003cimg src=\"https://www.codefactor.io/repository/github/easymem/easy_memory/badge\" alt=\"CodeFactor\"\u003e\u003c/a\u003e\n        \u003ca href=\"https://codecov.io/gh/easymem/easy_memory\"\u003e\u003cimg src=\"https://codecov.io/gh/easymem/easy_memory/graph/badge.svg\" alt=\"codecov\"\u003e\u003c/a\u003e\n        \u003ca href=\"https://github.com/easymem/easy_memory/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/easymem/easy_memory/actions/workflows/ci.yml/badge.svg\" alt=\"CI\"\u003e\u003c/a\u003e\n      \u003c/p\u003e\n    \u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n\u003cbr/\u003e\n\n**A strictly typed, platform-agnostic, and safe memory management system designed for high-performance and embedded applications.**\n\n## TL;DR\n\n**What is it?** A portable memory management system that replaces standard `malloc`/`free` with advanced capabilities like arbitrary alignment, scoped lifecycles, and fragmentation-resistant strategies.\n\n**Why use it?** To get deterministic, safe, and efficient memory control on any architecture—from x86 servers to bare-metal microcontrollers (ARM, Xtensa, etc.)—without the overhead of an OS.\n\n**How to use it?** `#define EASY_MEMORY_IMPLEMENTATION` in one `.c` file, then just `#include \"easy_memory.h\"`.\n\n## Key Features\n\n*   **Adaptive Performance:** Optimized for real-world usage patterns. Sequential allocations and LIFO deallocations (stack-like behavior) are detected and handled in **O(1)** time via the tail block. Complex, mixed-order patterns gracefully fallback to the efficient **O(log n)** tree search.\n*   **Compiler Agnostic \u0026 Optimization Resilient:** Verified to work correctly across all optimization levels:\n    *   **GCC/Clang:** `-O1` through `-O3`, `-Os`, and `-Oz`.\n    *   **MSVC:** `/O1`, `/O2`, and `/Ox`.\n    *   Strict compliance with **Strict Aliasing** rules ensures that aggressive compiler optimizations never break memory logic.\n*   **Triple-Key LLRB Tree:** Free blocks are sorted by **Size**, **Alignment Quality** (CTZ), and **Address**. This reduces fragmentation by prioritizing blocks that *naturally* satisfy alignment requirements before splitting new memory.\n*   **Flexible Alignment:** Supports per-allocation alignment requests (powers of two, up to **512 bytes**). Ideal for SIMD vectors and cache-line aligned buffers.\n*   **Low Overhead:** Metadata consumes only **4 machine words** per block (16 bytes on 32-bit, 32 bytes on 64-bit).\n*   **Bit-Packed Efficiency:** Alignment exponents are packed into the size field, and flags utilize pointer tagging. This results in minimal metadata overhead per block.\n*   **Modular Sub-Allocators:** Designed as a foundation for specialized allocators. All sub-allocators have **zero-overhead creation** (cost equivalent to a single standard allocation).\n    *   **Bump:** O(1) linear allocator (Available).\n    *   *Stack / Slab:* (Coming soon).\n*   **Scoped Memory:** Supports `em_create_nested` for hierarchical memory management. Freeing a parent scope instantly invalidates all children with O(1) complexity.\n*   **Tail-End Scratchpad:** Instantly reserves a block at the highest memory address (**O(1)**). Ideal for temporary workspaces to prevent fragmentation of the main heap. Fully integrated with standard `em_free`.\n*   **Concurrency Model:** Intentionally lock-free and single-threaded to avoid mutex overhead. Designed for **Thread-Local Storage (TLS)** patterns (one `EM` instance per thread).\n*   **Safety First:**\n    *   **XOR-Magic:** Headers are protected by address-dependent magic numbers to detect buffer underflows.\n    *   **Strict Validation:** Runtime checks ensure integrity of the heap structure.\n*   **Embedded Ready:** No `libc` dependency. Can run on bare metal (`EM_NO_MALLOC`).\n*   **Extreme Portability:** Verified across a wide range of compilers, operating systems, hardware architectures, and endianness types. (See *Verified Platforms* below).\n*   **Full C++ Compatibility:** Wrapped in `extern \"C\"` for seamless integration into C++ projects.\n*   **Excellent Developer Experience:**\n    *   **Intuitive API:** Consistent `em_*` naming convention.\n    *   **Source-Agnostic:** A single set of functions works on static, dynamic, and nested memory.\n    *   **Self-Documenting:** The codebase features encyclopedic comments explaining the *physics* and *rationale* behind every architectural decision.\n    *   **Visual Debugging:** Optional `print_fancy` function provides detailed, colorized visualizations of the memory layout.\n\n## Rigorous Validation\n\nThe system is subjected to exhaustive verification across diverse environments and configurations:\n\n*   **Sanitizer Suite:** Verified with **ASan** (Address), **UBSan** (Undefined Behavior), and **LSan** (Leak) across multiple architectures to ensure memory integrity and zero leaks.\n*   **Valgrind Memcheck:** **0 errors from 0 contexts**. Clean diagnostic logs ensure that library internals do not interfere with application-level debugging.\n*   **Optimization Resilient:** Proven stability across aggressive compiler optimization levels:\n    *   **GCC/Clang:** `-O1`, `-O2`, `-O3`, `-Os`, and `-Oz`.\n    *   **MSVC:** `/O1`, `/O2`, and `/Ox`.\n    *   Full compliance with **Strict Aliasing** rules guaranteed.\n*   **Pedantic Compilation:** Strictly enforced \"Warnings-as-Errors\" policy (`-Werror`) using an extensive flag set:\n    *   **Safety \u0026 Alignment:** `-Wshadow`, `-Wconversion`, `-Wundef`, `-Wstrict-aliasing=2`, `-Wcast-align`, `-Wpadded`.\n    *   **Portability:** `-Wint-to-pointer-cast`, `-Wpointer-to-int-cast`, `-Wdouble-promotion`, `-Wpointer-arith`.\n    *   **Code Integrity:** `-Wmissing-prototypes`, `-Wstrict-prototypes`, `-Wmissing-declarations`.\n*   **Static Analysis:** Continuous monitoring via **MSVC Static Analysis** (x64/x86), **Clang-Tidy**, and **CodeFactor** (Grade A+).\n*   **Platform Coverage:** Verified compatibility with **Windows (MSVC \u0026 MinGW)**, **Linux**, and **macOS**.\n\n## Architecture\n\nAt its core, `easy_memory` is a hierarchical system. It abstracts complex memory management logic into a unified API, delegating actual storage strategies to specialized components.\n\n```text\n                  ┌──────────────────────────────────────┐\n                  │      MEMORY MANAGEMENT SYSTEM        │\n                  │            easy_memory               │\n                  └──────────────────────────────────────┘\n                                     │\n        ┌────────────────────────────┼────────────────────────────┐\n        │                            │                            │\n        ▼                            ▼                            ▼\n   ┌─────────┐                 ┌────────────┐               ┌────────────┐\n   │  Arena  │                 │    Sub-    │               │ Scratchpad │\n   │ (core)  │                 │ allocators │               │   (temp)   │\n   └────┬────┘                 └─────┬──────┘               └────────────┘\n        │                            │\n        ▼                   ┌────────┼────────┐\n   ┌───────────┐            │        │        │\n   │  Adaptive │            ▼        ▼        ▼\n   │ BUMP O(1) │        ┌──────┐ ┌───────┐ ┌──────┐\n   │ LIFO O(1) │        │ Bump │ │ Stack │ │ Slab │\n   │ O(logn)   │        │ O(1) │ │ O(1)  │ │ O(1) │\n   └───────────┘        └──────┘ └───────┘ └──────┘\n```\n\n### 1. The Core (Arena)\nThe backbone of the system. It handles the heavy lifting of block splitting, merging, and alignment.\n*   **Origin:** This core logic is an evolution of the [**arena_c**](https://github.com/gooderfreed/arena_c) project, refined for stricter alignment support and bit-packed metadata.\n*   **Adaptive Strategy:** It doesn't blindly search the tree. If you allocate sequentially, it acts as a fast O(1) bump allocator using the tail block. If you free in LIFO order (stack-like), it merges instantaneously. It only falls back to the O(log n) Tree Search when memory becomes fragmented.\n*   **Triple-Key Tree:** When searching for gaps, it finds the *best* block not just by size, but by alignment quality, preserving large contiguous chunks.\n\n### 2. Scratchpad (Lifecycle Isolation)\nA mechanism to allocate a **single dedicated block** at the very end of the memory pool (highest address).\n\n*   **Purpose:** Acts as an anchor point for temporary memory contexts. By placing a temporary sub-allocator (like `Bump` or `Nested Scope`) at the extreme end of memory, you maximize the contiguous space available for the main heap.\n*   **Strict O(1) Performance:** Allocation simply reserves the tail space, and deallocation restores the previous state. No tree searches involved.\n*   **Unified Lifecycle:** **No special deallocation functions required.** The system automatically detects scratch blocks within the standard `em_free()` or `em_destroy()` calls.\n    *   Raw Memory: `em_alloc_scratch` → `em_free`\n    *   Scratch EM: `em_create_scratch` → `em_destroy`\n    *   Bump Allocator: `em_bump_create_scratch` → `em_bump_destroy`\n*   **Constraint:** Only one scratch allocation is active at a time per `EM` instance.\n\n### 3. Sub-Allocators\nSpecialized tools for specific allocation patterns. They are created *inside* a parent Core/Arena with zero overhead.\n*   **Bump Allocator:** A linear allocator that only moves a pointer forward. Ideal for frame-based rendering or parsing where deallocation happens all at once.\n*   *(Planned: Stack \u0026 Slab allocators for LIFO and fixed-size object pools).*\n\n## Architectural Philosophy\n\nMemory allocation strategies always involve a fundamental trade-off between three desirable properties: **cache locality**, **pointer stability**, and the ability to **resize** allocations. You can only pick two.\n\nThis library makes a deliberate architectural choice to prioritize **locality and stability**, which are often the most critical factors for high-performance systems like games, servers, and embedded applications.\n\n![Tradeoffs](.github/assets/design_tradeoffs.jpeg)\n\n### Principle 1: Pointers are Stable (No `realloc`)\nOnce memory is allocated from the system, its address will **never** change during its lifetime. This pointer stability allows you to safely store pointers to allocated objects without worrying about them becoming invalidated by a resize operation.\n*   **No `realloc` Equivalent:** Consequently, the library does not provide a direct equivalent of `realloc`. Resizing a block in-place is not possible without potentially moving subsequent blocks, which would violate the stable pointer guarantee.\n\n### Principle 2: Memory is Local (Performance by Default)\nThe system allocates memory sequentially from large, contiguous chunks. This dramatically improves cache performance compared to standard `malloc`, which can scatter allocations across the heap.\n\n### Principle 3: Concurrency is Isolated (Lock-Free)\nStandard allocators often use global locks to protect the heap, causing thread contention and context switching overhead. `easy_memory` contains **no internal mutexes or atomics**.\n\n*   **The Model:** The library is designed for **Thread-Local Allocation** patterns. Each thread should own its own `EM` instance (or a dedicated nested scope).\n*   **The Benefit:** Zero synchronization overhead. Allocation speed remains deterministic and blazing fast regardless of the number of active threads.\n*   **Safety Note:** If multiple threads must share a single *parent* arena to create nested scopes, access to that parent must be externally synchronized. Once created, the nested arena is independent.\n\n## Usage\n\n### 1. Integration\nInclude the header and define the implementation in **one** source file.\n\n```c\n#define EASY_MEMORY_IMPLEMENTATION\n// #define EM_NO_MALLOC // Uncomment for bare-metal usage\n#include \"easy_memory.h\"\n```\n\n### Alternative Integration for Large Projects\n\nIn complex projects with intricate include hierarchies, ensuring that `EASY_MEMORY_IMPLEMENTATION` is defined in exactly one `.c` file can be challenging. An alternative approach is to compile the header file directly into its own object file.\n\nYou can achieve this by adding a specific build rule to your build system (e.g., Makefile, CMake). Here's an example using `gcc`:\n\n```bash\n# Example Makefile rule\neasy_memory.o: easy_memory.h\n\tgcc -x c -DEASY_MEMORY_IMPLEMENTATION -c easy_memory.h -o easy_memory.o\n```\n\nThis command tells the compiler to treat `easy_memory.h` as a C source file, define `EASY_MEMORY_IMPLEMENTATION`, and compile it into an object file named `easy_memory.o`. You can then link this object file with the rest of your project.\n\n### 2. Standard Usage \u0026 Control\nBasic allocation, zero-initialization, and fast resetting.\n\n```c\n// Create a 1MB memory context on the heap\nEM *em = em_create(1024 * 1024);\n\n// Standard allocation\nMyObject *obj = (MyObject *)em_alloc(em, sizeof(MyObject));\n\n// Zero-initialized allocation (like calloc)\nPoint *pts = (Point *)em_calloc(em, 10, sizeof(Point));\n\n// Free individual block\nem_free(obj);\n\n// Reset the entire context in O(1)\n// Marks all memory as free without releasing the underlying buffer\nem_reset(em); \n\nem_destroy(em);\n```\n\n### 3. Alignment Control (Global \u0026 Per-Allocation)\nEnforce strict memory boundaries globally for an entire context (including nested sub-arenas), or request specific alignment for individual blocks.\n\n```c\n// 1. Global: EVERY allocation is guaranteed 64-byte alignment\nEM *gpu_em = em_create_aligned(1024 * 1024, 64);\n// Note: You can also use em_create_nested_aligned() for sub-arenas\n\nvoid *buffer = em_alloc(gpu_em, 1024); // Automatically 64-byte aligned\n\n// 2. Per-Allocation: Request a specific boundary on the fly\n// Allocate a single structure perfectly aligned to a 256-byte boundary,\n// forcing a stricter alignment than the arena's 64-byte baseline for this specific allocation.\nvoid *dma_struct = em_alloc_aligned(gpu_em, sizeof(MyDMAStruct), 256);\n```\n\n### 4. Nested Scopes (Hierarchical Memory)\nCreate sub-pools within a parent allocator. This provides memory isolation and safe bulk deallocation.\n\n```c\nvoid handle_request(EM *global_em) {\n    // Carve out a 64KB sub-context from the global memory\n    EM *request_scope = em_create_nested(global_em, 1024 * 64);\n    \n    // Allocations here act independently\n    char *buffer = (char *)em_alloc(request_scope, 1024);\n    \n    // Destroying the child instantly returns its 64KB block to the parent\n    em_destroy(request_scope); \n}\n```\n\n### 5. Bump Sub-Allocator (Trim \u0026 Reset)\nIdeal for high-speed temporary objects. Features `trim` to return unused memory to the parent, and `reset` for instant bulk clearing.\n\n```c\n// Reserve a large chunk (1MB) for the bump allocator\nBump *bump = em_bump_create(main_em, 1024 * 1024);\n\n// -- Scenario A: Asset Loading (Trim) --\nfor (int i = 0; i \u003c current_level_assets; ++i) {\n    em_bump_alloc(bump, asset_size[i]);\n}\n// Optimization: Return unused memory back to main_em\n// If we only used 600KB, the remaining 424KB is instantly freed back!\nem_bump_trim(bump); \n\n// -- Scenario B: Per-Frame Render Loop (Reset) --\nwhile (game_running) {\n    void *temp_obj = em_bump_alloc(bump, 256);\n    \n    // O(1) Reset: instantly invalidates all allocations made this frame,\n    // resetting the offset to the beginning without returning memory to the parent.\n    em_bump_reset(bump); \n}\n\nem_bump_destroy(bump);\n```\n\n### 6. Static / Bare Metal (No Malloc)\nIdeal for microcontrollers (STM32, AVR, RP2040, ESP32) or OS kernels.\n\n```c\n#define EASY_MEMORY_IMPLEMENTATION\n\n// Bare metal / no libc heap\n#define EM_NO_MALLOC\n// Prefer fail-fast contract checks (optional)\n#define EM_SAFETY_POLICY EM_POLICY_CONTRACT\n\n#include \"easy_memory.h\"\n\n// Pre-allocate memory in .bss or stack\nuint8_t pool[1024 * 32]; \n\nint main(void) {\n    // Initialize EM over the static buffer\n    // Returns NULL if the buffer is too small for metadata\n    EM *em = em_create_static(pool, sizeof(pool));\n\n    // ... use em_alloc as normal ...\n\n    return 0;\n}\n```\n\n### 7. Scratchpad (Temporary Tail Allocations | Lifecycle Isolation)\nThe scratchpad provides a universal mechanism to reserve memory at the extreme tail (highest address) of an EM instance in strict **O(1)** time. By anchoring temporary allocations here, contiguous space is preserved for the main heap.\n\n*   **Universal API:** Every creation function has a `_scratch` variant (`em_alloc_scratch`, `em_bump_create_scratch`, `em_create_scratch`).\n*   **Fully Functional:** A scratch entity is a 100% standard object. A nested `EM` created via scratch can host normal allocations, sub-allocators, or even its own inner scratchpad.\n*   **Single Slot Constraint:** Each `EM` instance supports exactly **one** active scratch allocation at a time.\n*   **Unified Lifecycle:** No special `*_scratch_free` or `*_scratch_destroy` functions exist. The standard deallocation API automatically detects scratch blocks and reclaims the tail.\n\n```c\nEM *root_em = em_create(1024 * 1024);\n\n// Normal allocations build up from the bottom\nvoid *persistent = em_alloc(root_em, 1024);\n\n// -- 1. Basic Scratch Allocation --\n// Uses the single scratch slot of root_em\nvoid *temp_buffer = em_alloc_scratch(root_em, 1024 * 64);\n// Unified cleanup detects the scratch block automatically\nem_free(temp_buffer); \n\n// -- 2. Advanced Scratch: Functional EM Instances --\n// Now the slot is free, we can use it to create a full nested EM at the tail\nEM *temp_scope = em_create_scratch(root_em, 1024 * 256);\n\n// Because temp_scope is a standard EM instance, it has its own independent scratch slot!\nBump *inner_bump = em_bump_create_scratch(temp_scope, 1024 * 64);\nvoid *ultra_temp = em_bump_alloc(inner_bump, 128);\n\n// -- Unified Cleanup --\nem_bump_destroy(inner_bump); \nem_destroy(temp_scope); // Instantly restores the 256KB tail in root_em\n```\n\n### 8. Visual Debugging\nThe library includes a built-in terminal visualizer to inspect memory fragmentation and layout.\n\n```c\n#define DEBUG\n#define EASY_MEMORY_IMPLEMENTATION\n#include \"easy_memory.h\"\n\nint main(void) {\n    EM *em = em_create(1024 * 64);\n    \n    em_alloc(em, 1024);\n    void *ptr = em_alloc(em, 512);\n    em_alloc_scratch(em, 2048);\n    \n    em_free(ptr); // Create a gap\n    \n    // Prints a colorized, 50-character wide visual representation of the heap\n    print_fancy(em, 50); \n    \n    return 0;\n}\n```\n\n## Configuration\n\nCustomize the library's behavior by defining macros **before** including `easy_memory.h`.\n\n### Runtime Safety Policies (`EM_SAFETY_POLICY`)\n\nControls the balance between absolute performance and runtime resilience.\n\n| Policy | Mode | Description | Recommended For |\n| :---: | :--- | :--- | :--- |\n| **0** | **CONTRACT** | **Design-by-Contract.** All checks are delegated to `EM_ASSERT`. Misuse leads to immediate abort (Debug) or UB (Release). | Performance-critical / Hardened Dev |\n| **1** | **DEFENSIVE** | **Fault-Tolerance (Default).** Performs robust 'if' checks. Gracefully returns `NULL` or exits on API misuse. | Production / General Purpose |\n\n\u003e **Note:** The final behavior of **CONTRACT** mode is determined by your [Assertion Strategy](#assertion-strategy).\n\n### Assertion Strategy\n\nDetermines how the library handles internal invariant violations.\n\n| Macro | Effect on Failure | Usage |\n| :--- | :--- | :--- |\n| **(Default)** | No-op | Assertions are compiled out. Safe for release. |\n| `DEBUG` | Calls `assert()` | Standard C behavior. Aborts with file/line information. |\n| `EM_ASSERT_STAYS` | Calls `assert()` | **Forces assertions to remain active** even in Release builds. |\n| `EM_ASSERT_PANIC` | Calls `abort()` | Hardened release. Prevents exploitability on heap corruption without leaking debug info. |\n| `EM_ASSERT_OPTIMIZE`| `__builtin_unreachable()` | **DANGER**. Uses assertions as compiler optimization hints. UB if condition is false. |\n| `EM_ASSERT(cond)` | **Custom** | Define this macro to implement custom error handling (e.g., logging, infinite loop, hardware reset). Overrides all other assertion flags. |\n\n### Memory Poisoning\n\nHelps detect use-after-free and uninitialized memory usage.\n\n| Macro | Description |\n| :--- | :--- |\n| **(Default)** | Disabled in Release, Enabled in `DEBUG`. |\n| `EM_POISONING` | Force **ENABLE** poisoning (even in Release). Fills freed memory with `EM_POISON_BYTE`. |\n| `EM_NO_POISONING` | Force **DISABLE** poisoning (even in `DEBUG`). Useful for performance profiling in debug builds. |\n| `EM_POISON_BYTE` | The byte value used for poisoning (Default: `0xDD`). |\n\n### System \u0026 Linkage\n\n| Macro | Description |\n| :--- | :--- |\n| `EASY_MEMORY_IMPLEMENTATION` | **Required.** Expands the implementation in the current translation unit. |\n| `EM_NO_MALLOC` | Disables `stdlib.h` dependency. Removes heap-based `em_create`, leaving only `em_create_static`. Essential for **Bare Metal**. |\n| `EM_STATIC` | Declares all functions as `static`, limiting visibility to the current translation unit. |\n| `EM_RESTRICT` | Manually define the `restrict` keyword if your compiler does not support auto-detection. |\n| `EM_NO_ATTRIBUTES` | Force-disables all compiler-specific attributes (`malloc`, `alloc_size`). **Note:** This is automatically enabled when both `EASY_MEMORY_IMPLEMENTATION` and `EM_STATIC` are defined to prevent pointer provenance issues during inlining. |\n\n### Fine-Tuning\n\n| Macro | Default | Description |\n| :--- | :--- | :--- |\n| `EM_DEFAULT_ALIGNMENT` | `16` | Baseline alignment for allocations (must be a power of two). |\n| `EM_MIN_BUFFER_SIZE` | `16` | Minimum usable size of a split block to prevent micro-fragmentation. |\n| `EM_MAGIC` | `0xDEADBEEF..` | Magic number used for block validation. Can be customized for uniqueness. |\n\n## Limitations \u0026 Roadmap\n\n### Thread Safety \u0026 Concurrency\nThe library is intentionally lock-free and not thread-safe out of the box. It contains no internal mutexes, atomics, or spinlocks. \n*   **Thread-Local Storage (TLS):** This is the intended and optimal use case. By provisioning a dedicated `EM` instance per thread, allocations remain deterministic and highly performant with zero thread contention or context-switching overhead.\n*   **Shared Arenas:** If memory must be allocated or freed from the *same* `EM` instance across multiple threads simultaneously, the `em_alloc` and `em_free` calls must be wrapped in external synchronization primitives. The library does not internally protect against race conditions.\n\n### MISRA C Non-Compliance (By Design)\nFor environments that mandate strict **MISRA C** compliance (e.g., critical aerospace or automotive systems), `easy_memory` is not a suitable choice.\n\nTo achieve extreme memory density (metadata overhead of only 4 machine words per block) and O(1) nested tracking, the architecture heavily relies on advanced C paradigms that MISRA explicitly forbids:\n*   **Pointer Tagging:** Metadata flags (e.g., `is_free`, `color`, `has_scratch`) are embedded directly into the least significant bits of valid pointers.\n*   **Type Punning \u0026 Unions:** `EM` and `Bump` structures physically masquerade as standard `Block` headers to their parent arenas, achieving zero-cost hierarchy tracking.\n*   **Pointer Arithmetic:** Extensive casting between pointers and `uintptr_t` is utilized to calculate absolute memory alignments and dynamic padding offsets.\n*   **XOR-Magic:** Pointers are XORed with `EM_MAGIC` numbers to validate memory provenance and dynamically detect alignment gaps.\n\nThese techniques are not code smells; they are the fundamental physics of how this allocator achieves its speed and compactness. Performance and memory density are deliberately prioritized over rigid coding standards.\n\n### Current Limitation: Stack Usage (Recursive Algorithms)\nThe current implementation of the LLRB tree (insertion, deletion, and balancing) relies on **recursion**. \n\n*   **Impact:** While efficient and readable, deep recursion may risk a **Stack Overflow** on severely constrained embedded platforms (e.g., AVR, Cortex-M0 with tiny stacks) if memory becomes highly fragmented, leading to a deep tree structure.\n*   **Mitigation:** On standard desktop/server environments or embedded systems with reasonable stack sizes, this is rarely an issue.\n*   **Call for Contribution:** Switching the LLRB logic to an **iterative (loop-based)** implementation is a high-priority goal to guarantee fixed stack usage. If you enjoy algorithmic challenges and non-recursive tree traversals, **Pull Requests are highly welcome!**\n\n### Upcoming Features\nThe following features are planned for future releases, prioritized by architectural importance:\n\n- [ ] **New Sub-Allocators:**\n    - **`Stack` Allocator:** A strict LIFO (Last-In-First-Out) allocator for temporary scopes, faster and lighter than nested arenas.\n    - **`Slab` Allocator:** A fixed-size block pool, ideal for reducing fragmentation when allocating many identical objects.\n- [ ] **Benchmark Suite:** A comprehensive set of automated benchmarks to verify performance claims against `malloc` and other allocators across different architectures.\n- [ ] **Statistics \u0026 Telemetry:** Optional, configurable collection of runtime metrics (total allocated bytes, high water mark/peak usage, fragmentation index) to aid in profiling.\n- [ ] **`Queue` Sub-Allocator:** A specialized FIFO (First-In-First-Out) allocator implementation (Ring Buffer strategy).\n\n## Build Status \u0026 Verified Platforms\n\nThe library is continuously integrated and tested across a matrix of OSs and Architectures.\n\n| OS      | Status                                                                                                                                                                                           |\n|---------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| Ubuntu  | ![Ubuntu Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=ubuntu-latest%20%7C%20x86_64%20%7C%20gcc\u0026label=ubuntu\u0026logo=ubuntu\u0026logoColor=white)         |\n| macOS   | ![macOS Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=macos-latest%20%7C%20x86_64%20%7C%20clang\u0026label=macOS\u0026logo=apple\u0026logoColor=white)           |\n| Windows | ![Windows Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=windows-latest%20%7C%20x86_64%20%7C%20gcc\u0026label=windows\u0026logo=windows\u0026logoColor=white)     |\n\n### By Compiler\n\n| Compiler    | Status                                                                                                                                                                                          |\n|-------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| GCC         | ![GCC Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=ubuntu-latest%20%7C%20x86_64%20%7C%20gcc\u0026label=gcc\u0026logo=gcc\u0026logoColor=white)                 |\n| GCC (MinGW) | ![GCC Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=windows-latest%20%7C%20x86_64%20%7C%20gcc\u0026label=gcc%20(mingw)\u0026logo=windows\u0026logoColor=white)  |\n| Clang       | ![Clang Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=ubuntu-latest%20%7C%20x86_64%20%7C%20clang\u0026label=clang\u0026logo=llvm\u0026logoColor=white)          |\n| MSVC        | ![MSVC Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=windows-latest%20%7C%20x86_64%20%7C%20gcc\u0026label=msvc\u0026logo=visualstudio\u0026logoColor=white)     |\n\n### By Architecture\n| Architecture | Endianness | OS / Environment | Status |\n| :--- | :--- | :--- | :--- |\n| `x86_64`  | Little  | Windows / Linux / macOS | ![x86_64 Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?branch=main\u0026job=build-and-test-x86_64\u0026label=x86_64\u0026logo=intel\u0026logoColor=white) |\n| `x86_32`  | Little  | Windows / Linux | ![x86_32 Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?branch=main\u0026job=build-and-test-32bit\u0026label=x86_32\u0026logo=intel\u0026logoColor=white) |\n| `AArch64` | Little  | Linux (Modern \u0026 Strict)  | ![ARM64 Modern Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?branch=main\u0026job=build-and-test-arm64-modern\u0026label=aarch64\u0026logo=arm\u0026logoColor=white) |\n| `ARMv7`   | Little  | Linux | ![ARM32 Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?job=Ubuntu%20%7C%20ARM32%20(armv7)%20%7C%20GCC\u0026label=armv7\u0026logo=arm\u0026logoColor=white) |\n| `s390x`   | **Big** | Linux | ![Big Endian Status](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?branch=main\u0026job=build-and-test-big-endian\u0026label=s390x\u0026logo=ibm\u0026logoColor=white) |\n\n### C Standards Compliance\n| Standard | Status |\n| :--- | :--- |\n| **C99 / C11 / C17 / C23** | ![C Standards](https://img.shields.io/github/actions/workflow/status/EasyMem/easy_memory/ci.yml?branch=main\u0026job=build-and-test-C-stds\u0026label=Passed) |\n\n### Hardware Verification (Bare Metal)\n\nThis library has been verified to run correctly on embedded hardware without standard library dependencies (`EM_NO_MALLOC`).\n\n| Architecture | Device | Status |\n| :--- | :--- | :--- |\n| **ARM Cortex-M0+** | Raspberry Pi Pico (RP2040) | ![Status](https://img.shields.io/badge/Verified-success) |\n| **Xtensa LX6** | ESP32-WROOM | ![Status](https://img.shields.io/badge/Verified-success) |\n\n## Why All This?\n*idk, i was bored*\n\n## Official Badges\n\nShow support by adding the EasyMem badge to your project's README.\n\nPreview | Markdown (Copy \u0026 Paste) |\n| :--- | :--- |\n| [![EasyMem](https://img.shields.io/badge/EasyMem-easy__memory-27272d?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory) | `[![EasyMem](https://img.shields.io/badge/EasyMem-easy__memory-27272d?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory)` |\n| [![Powered by easy_memory](https://img.shields.io/badge/Powered_by-easy__memory-27272d?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory) | `[![Powered by easy_memory](https://img.shields.io/badge/Powered_by-easy__memory-27272d?style=flat\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory)` |\n| [![EasyMem](https://img.shields.io/badge/EasyMem-easy__memory-27272d?style=flat-square\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory) | `[![EasyMem](https://img.shields.io/badge/EasyMem-easy__memory-27272d?style=flat-square\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory)` |\n| [![Powered by easy_memory](https://img.shields.io/badge/Powered_by-easy__memory-27272d?style=flat-square\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory) | `[![Powered by easy_memory](https://img.shields.io/badge/Powered_by-easy__memory-27272d?style=flat-square\u0026logo=github\u0026logoColor=white)](https://github.com/EasyMem/easy_memory)` |\n\n## Contributing\n\nContributions are welcome! Whether it's a bug fix, a new feature, or an improvement to the documentation, your input is valued. \n\nIf you find an edge case on a specific architecture or want to improve the test coverage, feel free to open an issue or submit a Pull Request.\n\n**Memory management in C doesn't have to be hard. Let's make it *easy*, together.**\n\n## License\nMIT License. See [LICENSE](LICENSE) for details.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasymem%2Feasy_memory","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Feasymem%2Feasy_memory","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Feasymem%2Feasy_memory/lists"}