-
-
Notifications
You must be signed in to change notification settings - Fork 862
refactor(allocator): introduce Alloc trait
#11198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,183 @@ | ||
| // All methods just delegate to `Bump`'s methods | ||
| #![expect(clippy::inline_always)] | ||
|
|
||
| use std::{ | ||
| alloc::{Layout, handle_alloc_error}, | ||
| ptr::NonNull, | ||
| }; | ||
|
|
||
| use allocator_api2::alloc::Allocator; | ||
| use bumpalo::Bump; | ||
|
|
||
| /// Trait describing an allocator. | ||
| /// | ||
| /// It's a simpler version of `allocator_api2`'s [`Allocator`] trait. | ||
| /// | ||
| /// The difference between these methods and [`Allocator`]'s versions of them are: | ||
| /// | ||
| /// * `shrink` and `grow` return a pointer and panic/abort if allocation fails, | ||
| /// instead of returning `Result::Err`. | ||
| /// * All methods return a `NonNull<u8>`, instead of `NonNull<[u8]>`. | ||
| pub trait Alloc { | ||
| /// Allocate space for an object with the given [`Layout`]. | ||
| /// | ||
| /// The returned pointer points at uninitialized memory, and should be initialized | ||
| /// with [`std::ptr::write`]. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics if reserving space for `layout` fails. | ||
| #[expect(dead_code)] | ||
| fn alloc(&self, layout: Layout) -> NonNull<u8>; | ||
|
|
||
| /// Deallocate the memory referenced by `ptr`. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `layout` must be the same [`Layout`] that block was originally allocated with. | ||
| #[expect(dead_code)] | ||
| unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout); | ||
|
|
||
| /// Grow an existing allocation to new [`Layout`]. | ||
| /// | ||
| /// If the allocation cannot be grown in place, the data from the whole of the old allocation | ||
| /// is copied to the start of the new allocation. | ||
| /// | ||
| /// If the allocation is grown in place, no memory copying will occur. | ||
| /// | ||
| /// Either way, the pointer returned points to the new allocation. | ||
| /// | ||
| /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was grown in-place. | ||
| /// The newly returned pointer is the only valid pointer for accessing this memory now. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. | ||
| /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. | ||
| #[expect(dead_code)] | ||
| unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> NonNull<u8>; | ||
|
|
||
| /// Shrink an existing allocation to new [`Layout`]. | ||
| /// | ||
| /// If the allocation cannot be shrunk in place, `new_layout.size()` bytes of data | ||
| /// from the old allocation are copied to the new allocation. | ||
| /// | ||
| /// If the allocation is shrunk in place, no memory copying will occur. | ||
| /// | ||
| /// Either way, the pointer returned points to the new allocation. | ||
| /// | ||
| /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was shrunk in-place. | ||
| /// The newly returned pointer is the only valid pointer for accessing this memory now. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. | ||
| /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. | ||
| #[expect(dead_code)] | ||
| unsafe fn shrink( | ||
| &self, | ||
| ptr: NonNull<u8>, | ||
| old_layout: Layout, | ||
| new_layout: Layout, | ||
| ) -> NonNull<u8>; | ||
| } | ||
|
|
||
| /// Implement [`Alloc`] for [`bumpalo::Bump`]. | ||
| /// | ||
| /// All methods except `alloc` delegate to [`Bump`]'s impl of `allocator_api2`'s [`Allocator`] trait. | ||
| impl Alloc for Bump { | ||
| /// Allocate space for an object with the given [`Layout`]. | ||
| /// | ||
| /// The returned pointer points at uninitialized memory, and should be initialized | ||
| /// with [`std::ptr::write`]. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics if reserving space for `layout` fails. | ||
| #[inline(always)] | ||
| fn alloc(&self, layout: Layout) -> NonNull<u8> { | ||
| self.alloc_layout(layout) | ||
| } | ||
|
|
||
| /// Deallocate the memory referenced by `ptr`. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `layout` must be the same [`Layout`] that block was originally allocated with. | ||
| #[inline(always)] | ||
| unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) { | ||
| // SAFETY: Safety requirements of `Allocator::deallocate` are the same as for this method | ||
| unsafe { self.deallocate(ptr, layout) } | ||
| } | ||
|
|
||
| /// Grow an existing allocation to new [`Layout`]. | ||
| /// | ||
| /// If the allocation cannot be grown in place, the data from the whole of the old allocation | ||
| /// is copied to the start of the new allocation. | ||
| /// | ||
| /// If the allocation is grown in place, no memory copying will occur. | ||
| /// | ||
| /// Either way, the pointer returned points to the new allocation. | ||
| /// | ||
| /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was grown in-place. | ||
| /// The newly returned pointer is the only valid pointer for accessing this memory now. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. | ||
| /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics / aborts if reserving space for `new_layout` fails. | ||
| #[inline(always)] | ||
| unsafe fn grow(&self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout) -> NonNull<u8> { | ||
| // SAFETY: Safety requirements of `Allocator::grow` are the same as for this method | ||
| let res = unsafe { Allocator::grow(&self, ptr, old_layout, new_layout) }; | ||
| match res { | ||
| Ok(new_ptr) => new_ptr.cast::<u8>(), | ||
| Err(_) => handle_alloc_error(new_layout), // panic/abort | ||
| } | ||
| } | ||
|
|
||
| /// Shrink an existing allocation to new [`Layout`]. | ||
| /// | ||
| /// If the allocation cannot be shrunk in place, the `layout.new()` bytes of data | ||
overlookmotel marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// from the old allocation are copied to the new allocation. | ||
| /// | ||
| /// If the allocation is shrunk in place, no memory copying will occur. | ||
| /// | ||
| /// Either way, the pointer returned points to the new allocation. | ||
| /// | ||
| /// Any access to the old `ptr` is Undefined Behavior, even if the allocation was shrunk in-place. | ||
| /// The newly returned pointer is the only valid pointer for accessing this memory now. | ||
| /// | ||
| /// # SAFETY | ||
| /// | ||
| /// * `ptr` must denote a block of memory currently allocated via this allocator. | ||
| /// * `old_layout` must be the same [`Layout`] that block was originally allocated with. | ||
| /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. | ||
| /// | ||
| /// # Panics | ||
| /// | ||
| /// Panics / aborts if reserving space for `new_layout` fails. | ||
| #[inline(always)] | ||
| unsafe fn shrink( | ||
| &self, | ||
| ptr: NonNull<u8>, | ||
| old_layout: Layout, | ||
| new_layout: Layout, | ||
| ) -> NonNull<u8> { | ||
| // SAFETY: Safety requirements of `Allocator::shrink` are the same as for this method | ||
| let res = unsafe { Allocator::shrink(&self, ptr, old_layout, new_layout) }; | ||
| match res { | ||
| Ok(new_ptr) => new_ptr.cast::<u8>(), | ||
| Err(_) => handle_alloc_error(new_layout), // panic/abort | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,7 @@ | |
| #![warn(missing_docs)] | ||
|
|
||
| mod address; | ||
| mod alloc; | ||
| mod allocator; | ||
| mod allocator_api2; | ||
| mod boxed; | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.