Skip to content

Commit 22992a9

Browse files
committed
feat: Add optimized grow()/shrink() functions for Pool
If resizing is requested for the last allocation in the pool, it may be possible to adjust pool data and avoid any real allocations.
1 parent b796695 commit 22992a9

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

src/core/pool.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,45 @@ unsafe impl Allocator for Pool {
6767
ngx_pfree(self.0.as_ptr(), ptr.as_ptr().cast());
6868
}
6969
}
70+
71+
unsafe fn grow(
72+
&self,
73+
ptr: NonNull<u8>,
74+
old_layout: Layout,
75+
new_layout: Layout,
76+
) -> Result<NonNull<[u8]>, AllocError> {
77+
debug_assert!(
78+
new_layout.size() >= old_layout.size(),
79+
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
80+
);
81+
self.resize_in_place(ptr, old_layout, new_layout, false)
82+
}
83+
84+
unsafe fn grow_zeroed(
85+
&self,
86+
ptr: NonNull<u8>,
87+
old_layout: Layout,
88+
new_layout: Layout,
89+
) -> Result<NonNull<[u8]>, AllocError> {
90+
debug_assert!(
91+
new_layout.size() >= old_layout.size(),
92+
"`new_layout.size()` must be greater than or equal to `old_layout.size()`"
93+
);
94+
self.resize_in_place(ptr, old_layout, new_layout, true)
95+
}
96+
97+
unsafe fn shrink(
98+
&self,
99+
ptr: NonNull<u8>,
100+
old_layout: Layout,
101+
new_layout: Layout,
102+
) -> Result<NonNull<[u8]>, AllocError> {
103+
debug_assert!(
104+
new_layout.size() <= old_layout.size(),
105+
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
106+
);
107+
self.resize_in_place(ptr, old_layout, new_layout, false)
108+
}
70109
}
71110

72111
impl AsRef<ngx_pool_t> for Pool {
@@ -229,6 +268,54 @@ impl Pool {
229268
p
230269
}
231270
}
271+
272+
/// Resizes a memory allocation in place if possible.
273+
///
274+
/// If resizing is requested for the last allocation in the pool, it may be
275+
/// possible to adjust pool data and avoid any real allocations.
276+
///
277+
/// # Safety
278+
/// This function is marked as unsafe because it involves raw pointer manipulation.
279+
unsafe fn resize_in_place(
280+
&self,
281+
ptr: NonNull<u8>,
282+
old_layout: Layout,
283+
new_layout: Layout,
284+
zeroize: bool,
285+
) -> Result<NonNull<[u8]>, AllocError> {
286+
if ptr.byte_add(old_layout.size()).as_ptr() == self.as_ref().d.last
287+
&& ptr.byte_add(new_layout.size()).as_ptr() <= self.as_ref().d.end
288+
&& ptr.align_offset(new_layout.align()) == 0
289+
{
290+
let pool = self.0.as_ptr();
291+
unsafe {
292+
(*pool).d.last = (*pool)
293+
.d
294+
.last
295+
.byte_offset(new_layout.size() as isize - old_layout.size() as isize)
296+
};
297+
Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size()))
298+
} else {
299+
let size = core::cmp::min(old_layout.size(), new_layout.size());
300+
let new_ptr = self.allocate(new_layout)?;
301+
unsafe {
302+
ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr().cast(), size);
303+
self.deallocate(ptr, old_layout);
304+
}
305+
Ok(new_ptr)
306+
}
307+
.inspect(|new_ptr| {
308+
if zeroize && new_layout.size() < old_layout.size() {
309+
unsafe {
310+
ptr::write_bytes(
311+
new_ptr.as_ptr().cast::<u8>().byte_add(new_layout.size()),
312+
0,
313+
old_layout.size() - new_layout.size(),
314+
)
315+
};
316+
}
317+
})
318+
}
232319
}
233320

234321
/// Cleanup handler for a specific type `T`.

0 commit comments

Comments
 (0)