implement rest of `GlobalAlloc`
By only implementing alloc and dealloc (and not realloc or alloc_zeroed) you introduce an additional and needless cost to using peak_alloc. Would you accept a pull request adding support for the other two methods?
Of course, I'd love to !
Not sure what the additional and needless cost is here.
Using the rust-analyzer LSP to insert the default implementation of realloc and alloc_zeroed yields the following code, which calls into alloc and dealloc ensuring that peak_alloc maintains a proper account of memory used.
Is the goal to optimize and consolidate the identical branch checks with !ptr.is_null() (one in each function: alloc, dealloc, realloc, alloc_zeroed)?
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let size = layout.size();
// SAFETY: the safety contract for `alloc` must be upheld by the caller.
let ptr = unsafe { self.alloc(layout) }; // !!! Null check 1 when alloc() called.
if !ptr.is_null() { // !!! Null check 2
// SAFETY: as allocation succeeded, the region from `ptr`
// of size `size` is guaranteed to be valid for writes.
unsafe { std::ptr::write_bytes(ptr, 0, size) };
}
ptr
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
// SAFETY: the caller must ensure that the `new_size` does not overflow.
// `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
// SAFETY: the caller must ensure that `new_layout` is greater than zero.
let new_ptr = unsafe { self.alloc(new_layout) }; // !!! Null check 1 when alloc() called.
if !new_ptr.is_null() { // !!! Null check 2
// SAFETY: the previously allocated block cannot overlap the newly allocated block.
// The safety contract for `dealloc` must be upheld by the caller.
unsafe {
std::ptr::copy_nonoverlapping(ptr, new_ptr, std::cmp::min(layout.size(), new_size));
self.dealloc(ptr, layout); // !!! Null check 3
}
}
new_ptr
}