Source code
Revision control
Copy as Markdown
Other Tools
use core::ptr::NonNull;↩
pub use std::alloc::System;↩
↩
use crate::stable::{assume, invalid_mut};↩
↩
use super::{AllocError, Allocator, GlobalAlloc as _, Layout};↩
↩
unsafe impl Allocator for System {↩
#[inline(always)]↩
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {↩
alloc_impl(layout, false)↩
}↩
↩
#[inline(always)]↩
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {↩
alloc_impl(layout, true)↩
}↩
↩
#[inline(always)]↩
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout) {↩
if layout.size() != 0 {↩
// SAFETY: `layout` is non-zero in size,↩
// other conditions must be upheld by the caller↩
unsafe { System.dealloc(ptr.as_ptr(), layout) }↩
}↩
}↩
↩
#[inline(always)]↩
unsafe fn grow(↩
&self,↩
ptr: NonNull<u8>,↩
old_layout: Layout,↩
new_layout: Layout,↩
) -> Result<NonNull<[u8]>, AllocError> {↩
// SAFETY: all conditions must be upheld by the caller↩
unsafe { grow_impl(ptr, old_layout, new_layout, false) }↩
}↩
↩
#[inline(always)]↩
unsafe fn grow_zeroed(↩
&self,↩
ptr: NonNull<u8>,↩
old_layout: Layout,↩
new_layout: Layout,↩
) -> Result<NonNull<[u8]>, AllocError> {↩
// SAFETY: all conditions must be upheld by the caller↩
unsafe { grow_impl(ptr, old_layout, new_layout, true) }↩
}↩
↩
#[inline(always)]↩
unsafe fn shrink(↩
&self,↩
ptr: NonNull<u8>,↩
old_layout: Layout,↩
new_layout: Layout,↩
) -> Result<NonNull<[u8]>, AllocError> {↩
debug_assert!(↩
new_layout.size() <= old_layout.size(),↩
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"↩
);↩
↩
match new_layout.size() {↩
// SAFETY: conditions must be upheld by the caller↩
0 => unsafe {↩
self.deallocate(ptr, old_layout);↩
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(↩
invalid_mut(new_layout.align()),↩
0,↩
)))↩
},↩
↩
// SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller↩
new_size if old_layout.align() == new_layout.align() => unsafe {↩
// `realloc` probably checks for `new_size <= old_layout.size()` or something similar.↩
assume(new_size <= old_layout.size());↩
↩
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);↩
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;↩
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(↩
ptr.as_ptr(),↩
new_size,↩
)))↩
},↩
↩
// SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,↩
// both the old and new memory allocation are valid for reads and writes for `new_size`↩
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap↩
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract↩
// for `dealloc` must be upheld by the caller.↩
new_size => unsafe {↩
let new_ptr = self.allocate(new_layout)?;↩
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), new_size);↩
self.deallocate(ptr, old_layout);↩
Ok(new_ptr)↩
},↩
}↩
}↩
}↩
↩
#[inline(always)]↩
fn alloc_impl(layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {↩
match layout.size() {↩
0 => Ok(unsafe {↩
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(↩
invalid_mut(layout.align()),↩
0,↩
))↩
}),↩
// SAFETY: `layout` is non-zero in size,↩
size => unsafe {↩
let raw_ptr = if zeroed {↩
System.alloc_zeroed(layout)↩
} else {↩
System.alloc(layout)↩
};↩
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;↩
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(↩
ptr.as_ptr(),↩
size,↩
)))↩
},↩
}↩
}↩
↩
// SAFETY: Same as `Allocator::grow`↩
#[inline(always)]↩
unsafe fn grow_impl(↩
ptr: NonNull<u8>,↩
old_layout: Layout,↩
new_layout: Layout,↩
zeroed: bool,↩
) -> Result<NonNull<[u8]>, AllocError> {↩
debug_assert!(↩
new_layout.size() >= old_layout.size(),↩
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"↩
);↩
↩
match old_layout.size() {↩
0 => alloc_impl(new_layout, zeroed),↩
↩
// SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`↩
// as required by safety conditions. Other conditions must be upheld by the caller↩
old_size if old_layout.align() == new_layout.align() => unsafe {↩
let new_size = new_layout.size();↩
↩
// `realloc` probably checks for `new_size >= old_layout.size()` or something similar.↩
assume(new_size >= old_layout.size());↩
↩
let raw_ptr = System.realloc(ptr.as_ptr(), old_layout, new_size);↩
let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;↩
if zeroed {↩
raw_ptr.add(old_size).write_bytes(0, new_size - old_size);↩
}↩
Ok(NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(↩
ptr.as_ptr(),↩
new_size,↩
)))↩
},↩
↩
// SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,↩
// both the old and new memory allocation are valid for reads and writes for `old_size`↩
// bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap↩
// `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract↩
// for `dealloc` must be upheld by the caller.↩
old_size => unsafe {↩
let new_ptr = alloc_impl(new_layout, zeroed)?;↩
core::ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), old_size);↩
System.deallocate(ptr, old_layout);↩
Ok(new_ptr)↩
},↩
}↩
}↩