Struct Scratchpad

Source
pub struct Scratchpad<BufferT, TrackingT>
where BufferT: Buffer, TrackingT: Tracking,
{ /* private fields */ }
Expand description

Stack-like dynamic memory pool with double-ended allocation support.

Scratchpad manages dynamic allocations from a fixed-size region of memory in a stack-like manner. Allocations can be made simultaneously from either the “front” or “back” of the scratchpad by setting a Marker using either mark_front() (returning a MarkerFront) or mark_back() (returning a MarkerBack). Multiple markers can be set, but only the most-recently set marker of a given type that is still active can be used to allocate objects.

Individual allocations can be made from the marker, but no memory is actually freed back into the pool until the marker is dropped, where all the memory allocated through the marker is released at once. If the marker is not the most-recently set active marker of its type, its memory will simply be flagged as unused until all markers of the same type that were created after it are also dropped, at which point the memory will be once again made available for allocations.

Scratchpad, Marker implementations, and Allocation all make use of static lifetimes to ensure that an object cannot be used after the object from which it was created is dropped (an allocation cannot outlive its marker, and a marker cannot outlive its scratchpad).

See also the crate-level documentation for more detailed information about how Scratchpad works and can be used.

Implementations§

Source§

impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where BufferT: Buffer, TrackingT: Tracking,

Source

pub fn new(buffer: BufferT, tracking: TrackingT) -> Self

Creates a new scratchpad instance.

Note that using large static arrays for allocation storage or marker tracking can cause the program to run out of stack space while calling this function. It is recommended to either use borrowed slices or boxed slices if this occurs, or alternatively use the unsafe static_new_in_place() function to create the Scratchpad.

§Examples
use scratchpad::Scratchpad;
use std::mem::MaybeUninit;

// Creates a scratchpad that can hold up to 256 bytes of data and up
// to 4 allocation markers. The initial contents of each buffer are
// ignored, so we can provide uninitialized data in order to reduce
// the runtime overhead of creating a scratchpad.
let scratchpad = unsafe { Scratchpad::new(
    MaybeUninit::<array_type_for_bytes!(MaybeUninit<u64>, 256)>::uninit().assume_init(),
    MaybeUninit::<array_type_for_markers!(MaybeUninit<usize>, 4)>::uninit().assume_init(),
) };
Source§

impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where BufferT: StaticBuffer, TrackingT: Tracking + StaticBuffer,

Source

pub fn static_new() -> Self

Creates a new instance for scratchpad types backed entirely by static arrays without initializing array memory.

Since static array Buffer and Tracking types are owned by the scratchpad, and their sizes are known ahead of time to the scratchpad type, scratchpads using only static arrays for storage can be created without having to provide any parameters.

Note that using large static arrays for allocation storage or marker tracking can cause the program to run out of stack space while calling this function. It is recommended to either use borrowed slices or boxed slices if this occurs, or alternatively use the unsafe static_new_in_place() function to create the Scratchpad.

It is strongly recommended to use arrays of MaybeUninit elements for both allocation and tracking storage if possible when using this function. Even though ByteData types can safely store any pattern of bits without causing undefined behavior, the rules in Rust for using integers whose memory is specifically uninitialized have not been finalized.

§Examples
use scratchpad::Scratchpad;
use std::mem::MaybeUninit;

// Creates a scratchpad that can hold up to 256 bytes of data and up
// to 4 allocation markers.
let scratchpad = Scratchpad::<
    array_type_for_bytes!(MaybeUninit<u64>, 256),
    array_type_for_markers!(MaybeUninit<usize>, 4),
>::static_new();
Source

pub unsafe fn static_new_in_place(dst: *mut Self)

Initializes a new instance in uninitialized memory for scratchpad types backed entirely by static arrays.

This is provided to allow for creation of scratchpads backed by large static arrays while guaranteeing that both arrays and the created Scratchpad are never accidentally stored on the stack, avoiding possible stack overflow.

It is strongly recommended to use arrays of MaybeUninit elements for both allocation and tracking storage if possible when using this function. Even though ByteData types can safely store any pattern of bits without causing undefined behavior, the rules in Rust for using integers whose memory is specifically uninitialized have not been finalized.

§Safety

This function is unsafe because it operates on a raw pointer.

It does not drop any existing contents of dst before writing, nor does it check for whether dst is a valid pointer.

dst must be properly aligned for storage of an instance of Scratchpad.

After returning, the contents of dst will need to be dropped when the scratchpad is no longer in use before the memory pointed to by dst is freed.

§Examples
use scratchpad::{CacheAligned, Scratchpad};
use std::mem::MaybeUninit;

// Scratchpad that can hold up to 1 MB of data and up to 16 allocation
// markers.
type LargeScratchpad = Scratchpad<
    array_type_for_bytes!(MaybeUninit<CacheAligned>, 1024 * 1024),
    array_type_for_markers!(MaybeUninit<usize>, 16),
>;

unsafe {
    // The `Vec` here represents any region of memory in which a
    // `Scratchpad` needs to be initialized at runtime, whether
    // allocated from the heap or elsewhere.
    let mut memory = Vec::with_capacity(1);
    memory.set_len(1);

    LargeScratchpad::static_new_in_place(memory.as_mut_ptr());

    let scratchpad = &memory[0];
    let marker = scratchpad.mark_front().unwrap();
    let allocation = marker.allocate(12).unwrap();
    assert_eq!(*allocation, 12);
}
Source§

impl<BufferT, TrackingT> Scratchpad<BufferT, TrackingT>
where BufferT: Buffer, TrackingT: Tracking,

Source

pub fn mark_front( &self, ) -> Result<MarkerFront<'_, BufferT, TrackingT>, Error<()>>

Creates a marker at the front of the allocation buffer for subsequent allocations.

§Examples
use scratchpad::Scratchpad;

let scratchpad = Scratchpad::<[u64; 1], [usize; 1]>::new([0], [0]);

let marker = scratchpad.mark_front().unwrap();
// `marker` can now be used for allocations...
Source

pub fn mark_back(&self) -> Result<MarkerBack<'_, BufferT, TrackingT>, Error<()>>

Creates a marker at the back of the allocation buffer for subsequent allocations.

§Examples
use scratchpad::Scratchpad;

let scratchpad = Scratchpad::<[u64; 1], [usize; 1]>::new([0], [0]);

let marker = scratchpad.mark_back().unwrap();
// `marker` can now be used for allocations...

Trait Implementations§

Source§

impl<BufferT, TrackingT> Debug for Scratchpad<BufferT, TrackingT>
where BufferT: Buffer, TrackingT: Tracking,

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<BufferT, TrackingT> !Freeze for Scratchpad<BufferT, TrackingT>

§

impl<BufferT, TrackingT> !RefUnwindSafe for Scratchpad<BufferT, TrackingT>

§

impl<BufferT, TrackingT> Send for Scratchpad<BufferT, TrackingT>
where BufferT: Send, TrackingT: Send,

§

impl<BufferT, TrackingT> !Sync for Scratchpad<BufferT, TrackingT>

§

impl<BufferT, TrackingT> Unpin for Scratchpad<BufferT, TrackingT>
where BufferT: Unpin, TrackingT: Unpin,

§

impl<BufferT, TrackingT> UnwindSafe for Scratchpad<BufferT, TrackingT>
where BufferT: UnwindSafe, TrackingT: UnwindSafe,

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> IntoMutSliceLikePtr<[T]> for T

Source§

fn into_mut_slice_like_ptr(ptr: *mut T) -> *mut [T]

Reinterprets a mutable pointer of this type as a SliceLike pointer. Read more
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.