Struct Stack

Source
pub struct Stack<'a> { /* private fields */ }
Expand description

A no-std compatible fixed-memory allocator that can be used with the musli crate.

It is geared towards handling few allocations, but they can be arbitrarily large. It is optimized to work best when allocations are short lived and “merged back” into one previously allocated region through Buffer::write_buffer.

It’s also optimized to write to one allocation “at a time”. So once an allocation has been grown once, it will be put in a region where it is unlikely to need to be moved again, usually the last region which has access to the remainder of the provided buffer.

For the moment, this allocator only supports 255 unique allocations, which is fine for use with the musli crate, but might be a limitation for other use-cases.

§Design

The allocator takes a buffer of contiguous memory. This is dynamically diviced into two parts:

  • One part which grows upwards from the base, constituting the memory being allocated.
  • Its metadata growing downward from the end of the buffer, containing headers for all allocated region.

By designing the allocator so that the memory allocated and its metadata is separate, neighbouring regions can efficiently be merged as they are written or freed.

Each allocation is sparse, meaning it does not try to over-allocate memory. This ensures that subsequent regions with initialized memory can be merged efficiently, but degrades performance for many small writes performed across multiple allocations concurrently.

Below is an illustration of this, where a and b are two allocations where we write one byte at a time to each. Here x below indicates an occupied gap in memory regions.

a
ab
# a moved to end
xbaa
# b moved to 0
bbaa
# aa not moved
bbaaa
# bb moved to end
xxaaabbb
# aaa moved to 0
aaaaxbbb
# bbb not moved
aaaaxbbbb
# aaaa not moved
aaaaabbbb
# bbbbb not moved
aaaaabbbbb
# aaaaa moved to end
xxxxxbbbbbaaaaaa
# bbbbb moved to 0
bbbbbbxxxxaaaaaa

Implementations§

Source§

impl<'a> Stack<'a>

Source

pub fn new(buffer: &'a mut [MaybeUninit<u8>]) -> Self

Build a new no-std allocator.

The buffer must be aligned by 8 bytes, and should be a multiple of 8 bytes.

See type-level documentation for more information.

§Panics

This method panics if called with a buffer larger than 2**31 or is provided a buffer which is not aligned by 8.

An easy way to align a buffer is to use StackBuffer when constructing it.

Trait Implementations§

Source§

impl Allocator for Stack<'_>

Source§

type Buf<'this> = StackBuf<'this> where Self: 'this

The type of an allocated buffer.
Source§

fn alloc(&self) -> Option<Self::Buf<'_>>

Allocate an empty, uninitialized buffer. Read more

Auto Trait Implementations§

§

impl<'a> !Freeze for Stack<'a>

§

impl<'a> !RefUnwindSafe for Stack<'a>

§

impl<'a> !Send for Stack<'a>

§

impl<'a> !Sync for Stack<'a>

§

impl<'a> Unpin for Stack<'a>

§

impl<'a> !UnwindSafe for Stack<'a>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.