Skip to content

Instantly share code, notes, and snippets.

@diwic
Last active December 20, 2016 12:15
Show Gist options
  • Save diwic/42f5eb598389fa4546f0ea857147086e to your computer and use it in GitHub Desktop.
Save diwic/42f5eb598389fa4546f0ea857147086e to your computer and use it in GitHub Desktop.
Safe alloca / stack slice abstraction - I hope?
use std::marker::PhantomData;
use std::{ptr, ops, slice, mem};
#[inline(always)]
fn stack_reserve<T>(count: usize) -> *mut T {
// This is for test purposes only - real version should call an alloca intrinsic instead
let mut v = Vec::with_capacity(count);
let z = v.as_mut_ptr();
mem::forget(v);
z
}
pub struct StackSlice<'a, T>(*mut T, usize, PhantomData<(T, &'a mut ())>);
impl<'a, T> StackSlice<'a, T> {
// Only to be called by macro
pub unsafe fn make<'b>(z: &'b mut *mut T, count: usize) -> StackSlice<'b, T> {
StackSlice(*z, count, PhantomData)
}
}
macro_rules! stack_slice {
// This macro creates a stack slice and initializes it with "val"
($i: ident = [$val: expr; $count: expr]) => {
let c = $count;
let mut secret_variable = stack_reserve(c);
for idx in 0..c {
let v = $val;
unsafe { ptr::write(secret_variable.offset(idx as isize), v) }
}
let mut $i = unsafe { StackSlice::make(&mut secret_variable, c) };
$i = $i; // Hide unused_mut warning
};
// This macro creates a stack slice and initializes it with values from an
// ExactSizeIterator.
($i: ident: [$t: ty] = $iter: expr) => {
let mut iter: &mut ::std::iter::ExactSizeIterator<Item=$t> = &mut $iter;
let c = iter.len();
let mut secret_variable = stack_reserve(c);
for idx in 0..c {
let v = iter.next().unwrap();
unsafe { ptr::write(secret_variable.offset(idx as isize), v) }
}
let mut $i = unsafe { StackSlice::make(&mut secret_variable, c) };
$i = $i; // Hide unused_mut warning
};
}
impl<'a, T> ops::Deref for StackSlice<'a, T> {
type Target = [T];
fn deref(&self) -> &[T] { unsafe { slice::from_raw_parts(self.0, self.1) } }
}
impl<'a, T> ops::DerefMut for StackSlice<'a, T> {
fn deref_mut(&mut self) -> &mut [T] { unsafe { slice::from_raw_parts_mut(self.0, self.1) } }
}
impl<'a, T> Drop for StackSlice<'a, T> {
fn drop(&mut self) {
for qq in &mut **self { unsafe { ptr::drop_in_place(qq) }}
}
}
fn test() {
stack_slice!(f = [String::from("Mooh"); 12]);
f[0] = "Hi".into();
assert_eq!(&*f[0], "Hi");
assert_eq!(&*f[11], "Mooh");
stack_slice!(g: [i32] = (0..57));
assert_eq!(g.len(), 57);
assert_eq!(g[15], 15);
}
/*
// Uncomment this function to see that compilation fails when we try to
// return a stack slice from a function.
fn compile_fail<'a>() -> StackSlice<'a, u8> {
stack_slice!(f = [5u8; 14]);
f
}
*/
fn main () {
test();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment