A self-contained C++ memory allocator and container library. Built entirely
with C++20/23 modules (import std), serving also as a testbed for idiomatic
modern C++: concepts, deducing this, std::ranges integration, modules-only
builds, and constant evaluation wherever the object model permits it.
Compiler support for C++26 modules is still evolving; the library targets Clang >= 22 and GCC >= 15.
| Component | Description |
|---|---|
slab |
Fixed-size block allocator with compile-time bitmap tracking. |
multislab |
Auto-expanding chain of slabs with hysteresis-based shrink policy. |
arena |
Bump/region allocator for trivially-destructible types. |
typed_arena |
Bump allocator with LIFO destructor chain for arbitrary types. |
pool |
Pointer-stable typed container (bitmap-based object pool) over multislab. |
spsc_ring |
Lock-free single-producer single-consumer ring buffer with cached indices; constinit-able. |
vector |
Contiguous growable sequence. |
small_vector |
Same, holding its first N elements inline and spilling past them. |
inline_vector |
Same, bounded at N inline elements; allocates nothing, ever, and works at compile time. |
fixed_vector |
Same, bounded at N with the slots on a resource instead of inline. |
sparse_set |
Dense-packed id set, O(1) insert / erase / contains, contiguous iteration. |
sparse_map |
sparse_set plus a payload per id; keys() and values() stay index-aligned. |
resource_allocator |
Standard Allocator over any libmem resource, so an arena can back a std::vector. |
allocator_resource |
The mirror: a standard Allocator backing a libmem container. |
Everything lives in a single module (import libmem;) with partitions.
Containers do not hard-code their buffer. Each takes a storage argument that
owns raw space and nothing else, so one container serves an inline buffer, a
resource-backed fixed buffer, a growing heap buffer, or a small-buffer-optimised
one without touching its own logic. The four kinds, the growth protocol and the
resource interface are in docs/storage.md.
libmem::spsc_ring<command, 64> small{}; // slots inline, no allocation
libmem::heap_spsc_ring<command, 1 << 20> big{}; // same ring, slots on the heap
libmem::small_vector<hit, 8> hits{}; // allocates nothing until the 9th hitFailure is a return value, not an exception. push_back returns a T*,
reserve returns bool, and nothing throws std::bad_alloc. No container is
implicitly copyable either, since a copy constructor could not report the
failure; copying is explicit through clone() and try_clone(). Everything
moves, inline buffers included, and every move is noexcept. See
docs/containers.md.
The inline containers work at compile time. inline_vector, sparse_set
and sparse_map over inline storage constant-evaluate end to end for trivially
default-constructible and trivially destructible element types, at no cost in
size or alignment.
It interoperates both ways. A std::pmr::polymorphic_allocator can back a
libmem container, and resource_allocator turns any libmem resource into a
standard Allocator, so an arena can back a std::vector or std::map.
Intended for the places a general-purpose allocator is the wrong shape: an ECS
storing components by entity id, a frame arena reset every tick, a lock-free
command queue between two threads, hot paths where a std::vector of eight
elements should not touch the heap.
./scripts/make.sh # Debug, Clang (default)
./scripts/make.sh --gcc # Debug, GCC
./scripts/make.sh --release # Release, Clang
./scripts/make.sh --test # Build and run tests
./scripts/make.sh --shared # Shared libraryOr directly with CMake:
cmake -B build -G Ninja \
-DCMAKE_TOOLCHAIN_FILE=cmake/llvm_toolchain.cmake \
-DCMAKE_BUILD_TYPE=Debug \
-DLIBMEM_BUILD_TESTS=ON
cmake --build build
ctest --test-dir buildTo use it from another project, see docs/integration.md.
CI builds and runs the suite with both GCC and Clang on every push, under
AddressSanitizer + UndefinedBehaviorSanitizer, with the ring handoff also run
under ThreadSanitizer. Coverage-guided libFuzzer harnesses drive
multislab, sparse_set, and sparse_map; the two sparse ones are differential,
comparing every operation against a standard container.
This is an early-stage library, so treat that as what is exercised today rather than a guarantee of exhaustive coverage. Details in docs/testing.md.
- Storage: the four storage kinds, resources, the growth protocol, small-buffer support, constant evaluation, standard-container interop.
- Containers: the vector family, identifiers, sparse set and map, copying and moving, ranges interop, constant evaluation.
- Complexity: cost tables for every component.
- Testing: what the suites and fuzzers actually cover.
- Integration: consuming libmem from another CMake project.