Skip to content

Commit 07ce1f7

Browse files
ensh63bavshin-f5
authored andcommitted
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 9220dc0 commit 07ce1f7

File tree

1 file changed

+81
-0
lines changed

1 file changed

+81
-0
lines changed

src/core/pool.rs

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,54 @@ 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(ptr, old_layout, new_layout)
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+
#[allow(clippy::manual_inspect)]
95+
self.resize(ptr, old_layout, new_layout).map(|new_ptr| {
96+
unsafe {
97+
new_ptr
98+
.cast::<u8>()
99+
.byte_add(old_layout.size())
100+
.write_bytes(0, new_layout.size() - old_layout.size())
101+
};
102+
new_ptr
103+
})
104+
}
105+
106+
unsafe fn shrink(
107+
&self,
108+
ptr: NonNull<u8>,
109+
old_layout: Layout,
110+
new_layout: Layout,
111+
) -> Result<NonNull<[u8]>, AllocError> {
112+
debug_assert!(
113+
new_layout.size() <= old_layout.size(),
114+
"`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
115+
);
116+
self.resize(ptr, old_layout, new_layout)
117+
}
70118
}
71119

72120
impl AsRef<ngx_pool_t> for Pool {
@@ -229,6 +277,39 @@ impl Pool {
229277
p
230278
}
231279
}
280+
281+
/// Resizes a memory allocation in place if possible.
282+
///
283+
/// If resizing is requested for the last allocation in the pool, it may be
284+
/// possible to adjust pool data and avoid any real allocations.
285+
///
286+
/// # Safety
287+
/// `ptr` must point to allocated address and `old_layout` must match the current layout
288+
/// of the allocation.
289+
#[inline(always)]
290+
unsafe fn resize(
291+
&self,
292+
ptr: NonNull<u8>,
293+
old_layout: Layout,
294+
new_layout: Layout,
295+
) -> Result<NonNull<[u8]>, AllocError> {
296+
if ptr.byte_add(old_layout.size()).as_ptr() == self.as_ref().d.last
297+
&& ptr.byte_add(new_layout.size()).as_ptr() <= self.as_ref().d.end
298+
&& ptr.align_offset(new_layout.align()) == 0
299+
{
300+
let pool = self.0.as_ptr();
301+
unsafe { (*pool).d.last = ptr.byte_add(new_layout.size()).as_ptr() };
302+
Ok(NonNull::slice_from_raw_parts(ptr, new_layout.size()))
303+
} else {
304+
let size = core::cmp::min(old_layout.size(), new_layout.size());
305+
let new_ptr = <Self as Allocator>::allocate(self, new_layout)?;
306+
unsafe {
307+
ptr.copy_to_nonoverlapping(new_ptr.cast(), size);
308+
self.deallocate(ptr, old_layout);
309+
}
310+
Ok(new_ptr)
311+
}
312+
}
232313
}
233314

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

0 commit comments

Comments
 (0)