diff --git a/src/lib.rs b/src/lib.rs index 1d3079a..537c9c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -117,5 +117,34 @@ where F: FnOnce(&mut [u8]) -> T }) } +#[inline(always)] fn align_buffer_to(ptr: *mut u8) -> *mut T +{ + use std::mem::align_of; + ((ptr as usize) + align_of::() - (ptr as usize) % align_of::()) as *mut T +} + +/// Allocate a runtime length slice of uninitialised `T` on the stack, call `callback` with this buffer, and then deallocate the buffer. +/// +/// See `alloca()`. +#[inline] pub fn stackalloc(size: usize, callback: F) -> U +where F: FnOnce(&mut [MaybeUninit]) -> U +{ + let size = (std::mem::size_of::() * size) + std::mem::align_of::(); + alloca(size, move |buf| { + let abuf = align_buffer_to::>(buf.as_mut_ptr() as *mut u8); + unsafe { + callback(slice::from_raw_parts_mut(abuf, size)) + } + }) +} + +/* note to self: aligning buffers manually: + +char buffer[sizeof(T) + alignof(T)]; +char* aligned_buffer = buffer + alignof(T) - reinterpret_cast(buffer) % alignof(T); +T* object = new (aligned_buffer) T; + + */ + #[cfg(test)] mod tests;