[−][src]Struct alloc_compose::Affix
An allocator that requests some extra memory from the parent allocator for storing a prefix and/or a suffix.
The alignment of the memory block is the maximum of the alignment of Prefix
and the requested
alignment. This may introduce an unused padding between Prefix
and the returned memory.
To get a pointer to the prefix or the suffix, the prefix()
and suffix()
may be called.
Performance
Generally it's faster to calculate the pointer to the prefix than the pointer to the suffix, as
the extended layout of Prefix
and the requested memory is needed in order to calculate the
Suffix
pointer. Additionally, in most cases it's recommended to use a prefix over a suffix for
a more efficient use of memory. However, small prefixes blunt the alignment so if a large
alignment with a small affix is needed, suffixes may be the better option.
For layouts known at compile time the compiler is able to optimize away almost all calculations.
Examples
Prefix
is 12
bytes in size and has an alignment requirement of 4
bytes. Suffix
is 16
bytes in size, the requested layout requires 28
bytes, both with an alignment of 8
bytes.
The parent allocator returns memory blocks of 128
bytes to demonstrate the behavior on
overallocating.
#![feature(allocator_api)] use alloc_compose::{Affix, Chunk}; use std::alloc::{Layout, System}; type Prefix = [u32; 3]; type Suffix = [u64; 2]; type Alloc = Affix<Chunk<System, 128>, Prefix, Suffix>; let layout = Layout::from_size_align(28, 8)?;
The memory layout differs depending on Prefix
and Suffix
:
use core::alloc::{AllocRef, AllocInit}; let mut my_alloc = Alloc::default(); // 0 12 16 44 48 64 128 // ╞═ Prefix ══╡ ╞════ requested memory ═════╡ ╞═══ Suffix ════╡ │ // ┢┳┳┳┳┳┳┳┳┳┳┳╅┬┬┬╆┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳┳╈┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╅┬┬╌╌╌╌┬┬┤ // ┡┻┻┻┻┻┻┻┻┻┻┻┹┴┴┴╄┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╇┻┻┻╇┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┹┴┴╌╌╌╌┴┴┘ // │ ├┄┄┄┄┄┄ layout.size() ┄┄┄┄┄┄┘ │ // │ ├┄┄┄┄┄┄┄┄┄ memory.size ┄┄┄┄┄┄┄┄┄┤ // └→ prefix() └→ memory.ptr └→ suffix() let memory = my_alloc.alloc(layout, AllocInit::Uninitialized)?; assert_eq!(memory.size, 32); unsafe { assert_eq!(Alloc::prefix(memory.ptr, layout).cast().as_ptr(), memory.ptr.as_ptr().sub(16)); assert_eq!(Alloc::suffix(memory.ptr, layout).cast().as_ptr(), memory.ptr.as_ptr().add(32)); }
The memory between Prefix
and the requested memory is unused. If there is a padding between
the requested memory and the suffix, this can be used as extra memory for the allocation. The
memory after Suffix
is also unused as Suffix
is typed. This results in 68
bytes unused
memory.
If Suffix
is a zero-sized type, the space after the requested memory block can be used:
use core::ptr::NonNull; // For convenience, the suffix can be ommitted type Alloc = Affix<Chunk<System, 128>, Prefix>; let mut my_alloc = Alloc::default(); // 0 12 16 44 48 64 128 // ╞═ Prefix ══╡ ╞════ requested memory ═════╡ │ │ │ // ┢┳┳┳┳┳┳┳┳┳┳┳╅┬┬┬╆┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳┳╈┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳╍╍╍╍┳┳┪ // ┡┻┻┻┻┻┻┻┻┻┻┻┹┴┴┴╄┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╇┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╍╍╍╍┻┻┩ // │ ├┄┄┄┄┄┄ layout.size() ┄┄┄┄┄┄┘ │ // │ ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ memory.size ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘ // └→ prefix() └→ memory.ptr let memory = my_alloc.alloc(layout, AllocInit::Uninitialized)?; assert_eq!(memory.size, 112); unsafe { assert_eq!(Alloc::prefix(memory.ptr, layout).cast().as_ptr(), memory.ptr.as_ptr().sub(16)); assert_eq!(Alloc::suffix(memory.ptr, layout), NonNull::dangling()); }
This results in only 4
bytes unused memory.
If Prefix
is a zero-sized type, this results in a waste of memory:
type Alloc = Affix<Chunk<System, 128>, (), Suffix>; let mut my_alloc = Alloc::default(); // 0 28 32 48 64 128 // ╞════ requested memory ═════╡ ╞═══ Suffix ════╡ │ │ // ┢┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳┳╈┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╅┬┬┬┬┬┬┬┬┬┬┬┬┬┬┬┼┬┬╌╌╌╌┬┬┤ // ┡┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╇┻┻┻╇┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┹┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴┴╌╌╌╌┴┴┘ // ├┄┄┄┄┄┄ layout.size() ┄┄┄┄┄┄┘ │ // ├┄┄┄┄┄┄┄┄┄ memory.size ┄┄┄┄┄┄┄┄┄┤ // └→ memory.ptr └→ suffix() let memory = my_alloc.alloc(layout, AllocInit::Uninitialized)?; assert_eq!(memory.size, 32); unsafe { assert_eq!(Alloc::prefix(memory.ptr, layout), NonNull::dangling()); assert_eq!(Alloc::suffix(memory.ptr, layout).cast().as_ptr(), memory.ptr.as_ptr().add(32)); }
This results in 80 bytes unused memory. As can be seen, if possible a prefix should be preferred to the suffix.
If both, Prefix
and Suffix
are ZSTs, this behaves like the parent allocator:
type Alloc = Affix<Chunk<System, 128>, (), ()>; let mut my_alloc = Alloc::default(); // 0 28 32 48 64 128 // ╞════ requested memory ═════╡ │ │ │ │ // ┢┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳┳╈┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳┳┳┳┳┳┳┳┳┳┳┳┳┳╈┳┳╍╍╍╍┳┳┪ // ┡┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╇┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻┻╍╍╍╍┻┻┩ // ├┄┄┄┄┄┄ layout.size() ┄┄┄┄┄┄┘ │ // ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄ memory.size ┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘ // └→ memory.ptr let memory = my_alloc.alloc(layout, AllocInit::Uninitialized)?; assert_eq!(memory.size, 128); unsafe { assert_eq!(Alloc::prefix(memory.ptr, layout), NonNull::dangling()); assert_eq!(Alloc::suffix(memory.ptr, layout), NonNull::dangling()); }
Fields
parent: Alloc
The parent allocator to be used as backend
Implementations
impl<Alloc, Prefix, Suffix> Affix<Alloc, Prefix, Suffix>
[src]
pub const fn new(parent: Alloc) -> Self
[src]
pub unsafe fn prefix(ptr: NonNull<u8>, layout: Layout) -> NonNull<Prefix>
[src]
Returns a pointer to the prefix.
Safety
ptr
must denote a block of memory currently allocated via this allocator, andlayout
must fit that block of memory.
pub unsafe fn suffix(ptr: NonNull<u8>, layout: Layout) -> NonNull<Suffix>
[src]
Returns a pointer to the suffix.
Safety
ptr
must denote a block of memory currently allocated via this allocator, andlayout
must fit that block of memory.
Trait Implementations
impl<Alloc, Prefix, Suffix> AllocRef for Affix<Alloc, Prefix, Suffix> where
Alloc: AllocRef,
[src]
Alloc: AllocRef,
fn alloc(
&mut self,
layout: Layout,
init: AllocInit
) -> Result<MemoryBlock, AllocErr>
[src]
&mut self,
layout: Layout,
init: AllocInit
) -> Result<MemoryBlock, AllocErr>
unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout)
[src]
unsafe fn grow(
&mut self,
ptr: NonNull<u8>,
old_layout: Layout,
new_size: usize,
placement: ReallocPlacement,
init: AllocInit
) -> Result<MemoryBlock, AllocErr>
[src]
&mut self,
ptr: NonNull<u8>,
old_layout: Layout,
new_size: usize,
placement: ReallocPlacement,
init: AllocInit
) -> Result<MemoryBlock, AllocErr>
unsafe fn shrink(
&mut self,
ptr: NonNull<u8>,
old_layout: Layout,
new_size: usize,
placement: ReallocPlacement
) -> Result<MemoryBlock, AllocErr>
[src]
&mut self,
ptr: NonNull<u8>,
old_layout: Layout,
new_size: usize,
placement: ReallocPlacement
) -> Result<MemoryBlock, AllocErr>
fn by_ref(&mut self) -> &mut Self
[src]
impl<Alloc: Clone, Prefix, Suffix> Clone for Affix<Alloc, Prefix, Suffix>
[src]
fn clone(&self) -> Self
[src]
fn clone_from(&mut self, source: &Self)
1.0.0[src]
impl<Alloc: Copy, Prefix, Suffix> Copy for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Debug, Prefix, Suffix> Debug for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Default, Prefix, Suffix> Default for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Eq, Prefix, Suffix> Eq for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: PartialEq, Prefix, Suffix> PartialEq<Affix<Alloc, Prefix, Suffix>> for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Send, Prefix, Suffix> Send for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Sync, Prefix, Suffix> Sync for Affix<Alloc, Prefix, Suffix>
[src]
impl<Alloc: Unpin, Prefix, Suffix> Unpin for Affix<Alloc, Prefix, Suffix>
[src]
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
fn to_owned(&self) -> T
[src]
fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,