diff --git a/src/core/pool.rs b/src/core/pool.rs index e8294f5..89bef82 100644 --- a/src/core/pool.rs +++ b/src/core/pool.rs @@ -67,6 +67,53 @@ unsafe impl Allocator for Pool { ngx_pfree(self.0.as_ptr(), ptr.as_ptr().cast()); } } + + unsafe fn grow( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + self.resize(ptr, old_layout, new_layout) + } + + unsafe fn grow_zeroed( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" + ); + self.resize(ptr, old_layout, new_layout).inspect(|new_ptr| { + unsafe { + ptr::write_bytes( + new_ptr.as_ptr().cast::().byte_add(old_layout.size()), + 0, + new_layout.size() - old_layout.size(), + ) + }; + }) + } + + unsafe fn shrink( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + debug_assert!( + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" + ); + self.resize(ptr, old_layout, new_layout) + } } impl AsRef for Pool { @@ -229,6 +276,43 @@ impl Pool { p } } + + /// Resizes a memory allocation in place if possible. + /// + /// If resizing is requested for the last allocation in the pool, it may be + /// possible to adjust pool data and avoid any real allocations. + /// + /// # Safety + /// `ptr` must point to allocated address and `old_layout` must match the current layout + /// of the allocation. + unsafe fn resize( + &self, + ptr: NonNull, + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { + if ptr.byte_add(old_layout.size()).as_ptr() == self.as_ref().d.last + && ptr.byte_add(new_layout.size()).as_ptr() <= self.as_ref().d.end + && ptr.align_offset(new_layout.align()) == 0 + { + let pool = self.0.as_ptr(); + unsafe { + (*pool).d.last = (*pool) + .d + .last + .byte_offset(new_layout.size() as isize - old_layout.size() as isize) + }; + Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size())) + } else { + let size = core::cmp::min(old_layout.size(), new_layout.size()); + let new_ptr = self.allocate(new_layout)?; + unsafe { + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), size); + self.deallocate(ptr, old_layout); + } + Ok(new_ptr) + } + } } /// Cleanup handler for a specific type `T`.