-
Notifications
You must be signed in to change notification settings - Fork 10
Description
Currently there's only Allocator trait that provides both allocations and deallocations.
And Box, Vec and other types has A: Allocator generic parameter.
However there are allocators with no-op deallocations and thus do not require collections and smart-pointers to keep any allocator state to deallocate.
It would reduce size and improve performance somewhat significantly if Box<T, A> would be able to use ZST A parameter if no state is required for deallocation and allocation is not needed.
I propose the following solution:
-
Split
Allocatortrait into two -DeallocatorandAllocator.
They can be defined as following.unsafe trait Deallocator { fn deallocate(&self, ptr: NonNull<u8>, layout: Layout); } unsafe trait Allocator: Deallocator { /* all other methods */ }
-
Define that deallocator
deallocator: Dcreated using<D as From<A>>::from(alloc)may deallocate memory allocated byalloc, any of its copy and equivalent allocators. -
Leave only
A: Deallocatorbound on collections and smart-pointers and all their impl blocks where allocation is not performed. -
Implement
From<Box<T, A>> for Box<T, D> where D: From<A>and similar impls for other types with allocator type.
This impl may conflict with others. The alternative is to add a method.
After this is done then allocators with possible no-op deallocation (like bumpalo::Bump or blink_alloc::BlinkAlloc) may define ZST deallocator type that does nothing on deallocation and only provides a lifetime to ensure that allocator is not reset.
On the bumpalo as example
struct Bumped<'a> {
_marker: PhantomData<&'a Bump>,
}
unsafe impl<'a> Deallocator for Bumped<'a> {
fn deallocate(&self, _ptr: NonNull<u8>, _layout: Layout) {}
}
impl<'a> From<&'a Bump> for Bumped<'a> {
fn from(_bump: &'a Bump) -> Self {
Bumped { _marker: PhantomData }
}
}
// Usage
fn foo<'a>(bump: &'a Bump) {
let box: Box<u32, &'a Bump> = Box::new_in(42, bump);
let box: Box<u32, Bumped<'a>> = box.into();
assert_eq!(size_of_val(&box), size_of::<usize>());
// Following doesn't compile as cloning `Box` requires `A: Allocator`
// let box2: Box<u32, _> = box.clone();
// If such ability is required - do not downgrade allocator to deallocator.
}