Skip to content

qaijuang/linalloc

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

40 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

linalloc (Linear Allocator)

CI MSRV crates.io docs.rs license

Small, lazy commit, fixed-capacity arena allocator for single-threaded Rust programs.

You pick the capacity up front. The arena capacity never grows. Raw bump allocations stay stable. When the arena is full, fallible allocation returns None.

Choose an arena

Type What it gives you Drop behavior
BumpArena Raw byte allocation from reserved virtual memory Values must be dropped by the caller
TypedArena<'a, T, A = BumpArena> Values of one type from a backing allocator Drops live values in reverse allocation order

Feature flags

  • nightly requires a nightly Rust toolchain and enables the unstable standard-library allocator_api implementation for BumpArena. Typed arenas backed by BumpArena also use that allocator for their internal tracking storage. The allocator implementation remains fixed-capacity, but grow, grow_zeroed, and shrink can relocate blocks into remaining arena capacity when in-place resizing is not possible, so allocator-managed blocks must use the pointer returned from successful resize operations.

Allocation APIs

Both arenas expose try_* for fallible allocation and alloc / alloc_* for the panicking variant. The 2.0 API intentionally keeps only BumpArena and TypedArena, the old lazy/ref arena names were removed.

Using bump arena

BumpArena gives you uninitialized bytes. You choose the layout, initialize the memory, and drop any values you place there.

use core::alloc::Layout;

use linalloc::BumpArena;

let arena = BumpArena::new(128);
let slot = arena.try_alloc_uninit(Layout::new::<u64>()).unwrap();
let ptr = slot.as_mut_ptr().cast::<u64>();

unsafe { ptr.write(42) };
assert_eq!(unsafe { *ptr }, 42);

With standard-library allocator

Enable nightly when you want bump arena to back standard-library collections that use the unstable allocator API:

[dependencies]
linalloc = { version = "2", features = ["nightly"] }
#![feature(allocator_api)]

# #[cfg(feature = "nightly")]
# {
    use linalloc::BumpArena;

    let arena = BumpArena::new(128);
    let mut values = Vec::with_capacity_in(1, &arena);

    values.push(1);
    values.try_reserve(1).unwrap();
    values.push(2);

    assert_eq!(&values, &[1, 2]);
# }

In typed arena as backing allocator

TypedArena<'a, T, A = BumpArena> stores initialized T values in a backing allocator A that implements the UninitAllocator trait and drops the live values when the arena is reset or dropped.

use linalloc::{BumpArena, TypedArena};

let bump = BumpArena::new(128); // Implements `UninitAllocator`
let mut foo_arena = TypedArena::<String>::new_in(&bump);
let mut bar_arena = TypedArena::<String>::new_in(&bump);

let foo = foo_arena.try_alloc("foo".to_owned()).unwrap();
let bar = bar_arena.try_alloc("bar".to_owned()).unwrap();

assert_eq!(foo, "foo");
assert_eq!(bar, "bar");

Reading OS errors

Bump arena keeps the raw OS code from the last failed reserve or commit call. Use it when try_new fails, or when allocation returns None and you need to know whether the OS refused more committed memory.

use core::alloc::Layout;

use linalloc::BumpArena;

if let Err(code) = BumpArena::try_new(usize::MAX) {
    assert_eq!(Some(code), std::io::Error::last_os_error().raw_os_error());
}


let arena = BumpArena::new(128);
let _slot = arena.try_alloc_uninit(Layout::new::<u64>()).unwrap();
assert_eq!(arena.last_os_error_code(), None);

Safety

Bump arenas hand you uninitialized bytes. Do not read them until you have written them. Values stored in bump arenas are not dropped automatically.

Typed arenas own initialized values. reset takes &mut self, drops live values in reverse allocation order, and clears the typed arena’s tracking. It does not rewind the backing allocator; reuse is governed by that allocator’s own reset/drop lifecycle.

For bump arenas, reset is unsafe. All returned slices must be dead, and any values stored in the arena must already have been dropped.

With nightly, BumpArena implements core::alloc::Allocator. Per-block deallocate is a no-op -- memory is reclaimed only by reset or by dropping the arena. grow, grow_zeroed, and shrink reuse the existing block when possible and otherwise may relocate it into remaining arena capacity. Relocated old blocks are logically deallocated but their bytes are not physically reclaimed until reset or drop. Drop all collections and values that use an arena allocator before calling reset.

About

Small, lazy commit, fixed-capacity arena allocators for single-threaded Rust programs.

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Contributors

Languages