commit f043a949c5600f421267a53ca8cbbe0f460669e4 Author: Avril Date: Wed Nov 11 14:58:46 2020 +0000 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..80aca69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +*~ diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..5e94c84 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "stack-vec" +version = "0.1.0" +authors = ["Avril "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..f8ebe82 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,606 @@ + +/// Create an ad-hoc sized `Vec`-like array on the stack. +/// +/// # Usage +/// ``` +/// # use stack_vec::stack; +/// let sv = stack![usize; 100]; +/// assert_eq!(sv.cap(), 100); +/// ``` +/// +/// Can be used mostly just like `Vec`, except the size must be a literal. +/// ``` +/// # use stack_vec::stack; +/// let mut sv = stack![12]; +/// for x in 0..12 { +/// sv.push(vec![x,x]); +/// } +/// assert_eq!(sv.into_iter().map(|x| x.into_iter().product::()).sum::(), (0..12).map(|x| x*x).sum::()); +/// ``` +/// # Defining `StackVec` types +/// You can also use this macro to define your own transparent `StackVec` types +/// ``` +/// # use stack_vec::stack; +/// stack!(pub type StackVec10 StackVec10IntoIter 10); +/// +/// let sv: StackVec10<_> = [1i32; 10].iter().copied().collect(); +/// let sv: StackVec10IntoIter<_> = sv.into_iter(); +/// assert_eq!(sv.sum::(), 10); +/// ``` +/// +/// See one of the `StackVec` structs defined here for more information. +#[macro_export] macro_rules! stack { + ($($q:tt)? type $name:ident $into_iter_name:ident $n:literal) => { + + #[allow(unused_doc_comments)] + #[doc="A sized stack vector"] + $($q)? struct $name([::std::mem::MaybeUninit; $n], usize); + + impl $name + { + #![allow(dead_code)] + + /// The max capacity of this `StackVec` type + pub const CAPACITY: usize = $n; + + /// The max capacity of this `StackVec` + /// + /// # Note + /// Identical to `Self::CAPACITY`, however more convenient for ad-hoc types created through `stack![n]`. + #[inline] pub const fn cap(&self) -> usize + { + Self::CAPACITY + } + + /// Create a new empty `StackVec`. + #[inline] pub fn new() -> Self + { + use std::mem::MaybeUninit; + unsafe { + Self(MaybeUninit::uninit().assume_init(), 0) // for now we can't make this `const fn` :( + } + } + + /// Extend from a slice where `T: Copy`. + /// + /// Returns the number of elements copied. If the copy would overflow the capacity the rest is ignored. + #[inline] pub fn extend_from_slice_copy>(&mut self, slice: U) -> usize + where T: Copy + { + let rest = unsafe {self.rest_mut()}; + let slice = slice.as_ref(); + let len = std::cmp::min(rest.len(),slice.len()); + + unsafe { + std::ptr::copy(slice.as_ptr(), rest.as_mut_ptr() as *mut std::mem::MaybeUninit as *mut T, len); + } + self.1+=len; + + len + } + + /// Extend from a slice where `T: Clone` + /// + /// Returns the number of elements copied. If the copy would overflow the capacity the rest is ignored. + pub fn extend_from_slice>(&mut self, slice: U) -> usize + where T: ::std::clone::Clone + { + let rest = &mut self.0[self.1..]; + let slice = slice.as_ref(); + + let mut wrote=0; + for (d,s) in rest.iter_mut().zip(slice.iter()) + { + *d = std::mem::MaybeUninit::new(s.clone()); + self.1+=1; + wrote+=1; + } + wrote + } + + /// Try to push an element on to the end of the `StackVec`. + /// + /// If it is full, return the value as `Err(T)` instead. + #[inline(always)] pub fn try_push(&mut self, value: T) -> Result<(), T> + { + if self.1 < Self::CAPACITY { + self.0[self.1] = std::mem::MaybeUninit::new(value); + self.1+=1; + Ok(()) + } else { + Err(value) + } + } + + /// Push an element on the the end of the `StackVec`. + /// + /// # Panics + /// If the `StackVec` is full. + #[inline] pub fn push(&mut self, value: T) + { + #[cold] fn off_end() -> ! { + panic!(concat!("Tried to push off the end of `StackVec", stringify!($n), "`")); + } + if self.1 < Self::CAPACITY { + self.0[self.1] = std::mem::MaybeUninit::new(value); + self.1+=1; + } else { + off_end() + } + } + + /// The number of elements currently in the `StackVec`. + #[inline] pub fn len(&self) -> usize + { + self.1 + } + + /// A slice of the elements in the `StackVec`. + #[inline(always)] pub fn as_slice(&self) -> &[T] + { + unsafe { &*(&self.0[..self.1] as *const [std::mem::MaybeUninit] as *const [T]) } + } + /// A mutable slice of the elements in the `StackVec`. + #[inline(always)] pub fn as_mut_slice(&mut self) -> &mut [T] + { + unsafe { &mut *(&mut self.0[..self.1] as *mut [std::mem::MaybeUninit] as *mut [T]) } + } + + /// A mutable slice of the initialised part of the buffer. + /// + /// All elements of the returned slice are initialised. + #[inline(always)] pub fn init_buffer_mut(&mut self) -> &mut [std::mem::MaybeUninit] + { + &mut self.0[..self.1] + } + + /// The initialised part of the buffer. + /// + /// All elements of the returned slice are initialised. + #[inline(always)] pub fn init_buffer(&self) -> &[std::mem::MaybeUninit] + { + &self.0[..self.1] + } + + /// A mutable reference to the uninitialised part of the instance. + /// + /// No elements of the returned slice are initialised. + /// # Note + /// If you initialise some, you must remember to update the length with `set_len()`. + #[inline(always)] pub unsafe fn rest_mut(&mut self) -> &mut [std::mem::MaybeUninit] + { + &mut self.0[self.1..] + } + /// The uninitialised part of the instance. + /// + /// No elements of the returned slice are initialised. + #[inline(always)] pub fn rest(&self) -> &[std::mem::MaybeUninit] + { + &self.0[self.1..] + } + + /// A mutable reference to the whole capacity buffer. + /// + /// `..self.len()` will be initialised, `self.len()..` will be uninitialised. + /// + /// # Note + /// If you initialise or uninitialise some element(s), you must remember to update the length with `set_len()`. + #[inline] pub unsafe fn buffer_mut(&mut self) -> &mut [std::mem::MaybeUninit; $n] + { + &mut self.0 + } + /// A reference to the whole capacity buffer. + /// + /// `..self.len()` will be initialised, `self.len()..` will be uninitialised. + #[inline] pub fn buffer(&self) -> &[std::mem::MaybeUninit; $n] + { + &self.0 + } + /// Set the internal fill pointer of the `StackVec`. + /// + /// This changes how much of the buffer is assumed to be initialised. + /// Only use this if you have manually initialised some of the uninitialised buffer, as it does no initialising itself. + #[inline] pub unsafe fn set_len(&mut self, len: usize) + { + self.1 = len; + } + } + + impl ::std::ops::Drop for $name + { + fn drop(&mut self) + { + if std::mem::needs_drop::() { + for init in &mut self.0[..self.1] + { + unsafe { + drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init()); + } + } + } + } + } + + + impl ::std::ops::DerefMut for $name + { + #[inline] fn deref_mut(&mut self) -> &mut Self::Target + { + self.as_mut_slice() + } + } + impl ::std::ops::Deref for $name + { + type Target = [T]; + + #[inline] fn deref(&self) -> &Self::Target + { + self.as_slice() + } + } + impl ::std::convert::AsRef<[T]> for $name + { + #[inline] fn as_ref(&self) -> &[T] + { + self.as_slice() + } + } + impl ::std::convert::AsMut<[T]> for $name + { + #[inline] fn as_mut(&mut self) -> &mut [T] + { + self.as_mut_slice() + } + } + impl ::std::borrow::Borrow<[T]> for $name + { + #[inline] fn borrow(&self) -> &[T] + { + self.as_slice() + } + } + impl ::std::borrow::BorrowMut<[T]> for $name + { + #[inline] fn borrow_mut(&mut self) -> &mut [T] + { + self.as_mut_slice() + } + } + impl ::std::fmt::Debug for $name + where T: ::std::fmt::Debug + { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result + { + write!(f, "{:?}", self.as_slice()) + } + } + impl ::std::cmp::Eq for $name + where T: ::std::cmp::Eq{} + impl ::std::cmp::PartialEq for $name + where T: ::std::cmp::PartialEq, + U: AsRef<[T]> + { + #[inline] + fn eq(&self, other: &U) -> bool + { + self.as_slice() == other.as_ref() + } + } + + impl ::std::cmp::Ord for $name + where T: ::std::cmp::Ord + { + #[inline] + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + std::cmp::Ord::cmp(self.as_slice(), other.as_slice()) + } + } + impl ::std::cmp::PartialOrd for $name + where T: ::std::cmp::PartialOrd, + U: AsRef<[T]> + { + #[inline] + fn partial_cmp(&self, other: &U) -> Option { + std::cmp::PartialOrd::partial_cmp(self.as_slice(), other.as_ref()) + } + } + + impl> std::ops::Index for $name + { + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &Self::Output { + std::ops::Index::index(self.as_slice(), index) + } + } + + impl> std::ops::IndexMut for $name + { + #[inline] + fn index_mut(&mut self, index: I) -> &mut Self::Output { + std::ops::IndexMut::index_mut(self.as_mut_slice(), index) + } + } + + + impl ::std::clone::Clone for $name + where T: ::std::clone::Clone + { + fn clone(&self) -> Self + { + let mut emp = Self::new(); + for (d,s) in emp.0.iter_mut().zip(self.iter()) + { + *d = std::mem::MaybeUninit::new(s.clone()); + emp.1+=1;//increment in case of `clone` panic + } + emp + } + } + impl ::std::convert::From<$name> for ::std::vec::Vec + { + #[inline] fn from(from: $name) -> Self + { + from.into_iter().collect() + } + } + impl std::default::Default for $name + { + #[inline] + fn default() -> Self + { + Self::new() + } + } + + + + impl ::std::iter::IntoIterator for $name + { + type Item= T; + type IntoIter = $into_iter_name; + + fn into_iter(self) -> Self::IntoIter + { + $into_iter_name(self, 0) + } + } + + impl ::std::io::Write for $name + { + fn write(&mut self, buf: &[u8]) -> ::std::io::Result + { + Ok(self.extend_from_slice_copy(buf)) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[::std::io::IoSlice<'_>]) -> ::std::io::Result { + let mut w = 0; + for buf in bufs { + w += self.extend_from_slice_copy(&buf[..]); + } + Ok(w) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> ::std::io::Result<()> { + let w = self.extend_from_slice_copy(buf); + if w!=buf.len() { + Err(::std::io::Error::new(::std::io::ErrorKind::Other, "No more space")) + } else { + Ok(()) + } + } + + #[inline] fn flush(&mut self) -> ::std::io::Result<()> + { + Ok(()) + } + } + + impl ::std::convert::From<[T; $n]> for $name + { + #[inline] fn from(from: [T; $n]) -> Self + { + let mut this = Self::new(); + unsafe { + std::ptr::copy(&from[0] as *const T, &mut this.0[0] as *mut std::mem::MaybeUninit as *mut T, $n); + } + this.1=$n; + std::mem::forget(from); + this + } + } + impl ::std::iter::FromIterator for $name + { + fn from_iter>(iter: I) -> Self + { + let mut output = Self::new(); + for item in iter + { + output.push(item); + } + output + } + } + + + pub struct $into_iter_name($name, usize); + + impl $into_iter_name + { + #![allow(dead_code)] + + pub fn rest(&self) -> &[std::mem::MaybeUninit] + { + &self.0.init_buffer()[self.1..] + } + pub fn rest_mut(&mut self) -> &mut [std::mem::MaybeUninit] + { + &mut self.0.init_buffer_mut()[self.1..] + } + } + impl std::iter::Iterator for $into_iter_name + { + type Item = T; + fn next(&mut self) -> Option + { + let buf = self.0.init_buffer_mut(); + if self.1 < buf.len() { + (unsafe { + Some(std::mem::replace(&mut buf[self.1], std::mem::MaybeUninit::uninit()).assume_init()) + },self.1+=1).0 + } else { + None + } + } + + fn size_hint(&self) -> (usize, Option) + { + (self.0.len(), Some(self.0.len())) + } + } + impl std::iter::ExactSizeIterator for $into_iter_name{} + impl std::iter::FusedIterator for $into_iter_name{} + impl std::ops::Drop for $into_iter_name + { + fn drop(&mut self) + { + if std::mem::needs_drop::() { + unsafe { + for init in self.rest_mut() { + + drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init()); + } + } + self.0.1=0; //prevent StackVec$n from trying to drop anything + } + } + } + + }; + ($t:ty; $n:literal) => { + { + $crate::stack!({} type StackVecN StackVecNIntoIter $n); + + StackVecN::<$t>::new() + } + }; + ($n:literal) => { + { + $crate::stack!({} type StackVecN StackVecNIntoIter $n); + + StackVecN::new() + } + }; +} + +stack!(pub type StackVec1 StackVec1IntoIter 1); +stack!(pub type StackVec2 StackVec2IntoIter 2); +stack!(pub type StackVec4 StackVec4IntoIter 4); +stack!(pub type StackVec8 StackVec8IntoIter 8); +stack!(pub type StackVec16 StackVec16IntoIter 16); +stack!(pub type StackVec32 StackVec32IntoIter 32); +stack!(pub type StackVec64 StackVec64IntoIter 64); +stack!(pub type StackVec128 StackVec128IntoIter 128); +stack!(pub type StackVec256 StackVec256IntoIter 256); +stack!(pub type StackVec512 StackVec512IntoIter 512); +stack!(pub type StackVec1024 StackVec1024IntoIter 1024); +stack!(pub type StackVec2048 StackVec2048IntoIter 2048); +stack!(pub type StackVec4096 StackVec4096IntoIter 4096); + +fn _assert_comp() +{ + let _svec: StackVec256 = StackVec256::new(); +} + +#[cfg(test)] +mod tests +{ + use super::*; + #[test] + fn push_and_drop() + { + let mut sv = StackVec256::new(); + sv.push(String::from("Hello")); + sv.push(String::from(" ")); + sv.push(String::from("world.")); + sv.push(String::from("!!!")); + sv.push(String::from("owo")); + + assert_eq!(sv.len(), 5); + assert_eq!("Hello world.", sv.into_iter().take(3).collect::().as_str()); + } + + #[test] + fn conversions() + { + let mut sv = StackVec256::new(); + assert_eq!(sv.extend_from_slice(&[vec![1usize,2],vec![3,4], vec![5,6]]), 3); + + assert_eq!(sv[1].iter().sum::(), 7); + assert_eq!(sv.iter().flat_map(|x| x.iter()).sum::(), 1+2+3+4+5+6); + + let v = Vec::from(sv.clone()); + assert_eq!(&v[..], &sv[..]); + drop(sv); + assert_eq!(v.iter().flat_map(|x| x.iter()).sum::(), 1+2+3+4+5+6); + } + + #[test] + fn write() + { + use std::io::Write; + let mut sv = StackVec256::new(); + let buf1 = [0u8; 128]; + let buf2 = [1u8; 128]; + + sv.write_all(&buf1[..]).expect("Failed to write buf1"); + sv.write_all(&buf2[..]).expect("Failed to write buf2"); + assert!(sv.write_all(&buf1[..]).is_err()); + + assert_eq!(&sv[..buf1.len()], &buf1[..]); + assert_eq!(&sv[buf1.len()..], &buf2[..]); + + assert_eq!(buf1.iter().chain(buf2.iter()).copied().collect::>(), sv.into_iter().collect::>()); + } + + #[test] + fn from_iterator() + { + let sv: StackVec256<_> = vec![1,2,3,4,5,6].into_iter().collect(); + assert_eq!(sv.into_iter().sum::(), 6+5+4+3+2+1i32); + + let nt: StackVec256<_> = vec![ + vec![1,2,3], + vec![4,5,6], + vec![7,8,9], + ].into_iter().collect(); + assert_eq!(nt.iter().flat_map(|x| x.iter()).copied().sum::(), 9+8+7+6+5+4+3+2+1); + } + + #[test] + #[should_panic] + fn from_too_big() + { + let _sv: StackVec256<_> = vec![vec![String::from("hi")]; 257].into_iter().collect(); + } + + #[test] + fn ad_hoc() + { + let mut sv = stack![23]; + + assert_eq!(sv.cap(), 23); + + for x in 0..23 + { + sv.push(vec![x,x]); + } + assert_eq!(sv.len(), 23); + + assert_eq!(sv.into_iter().flat_map(|x| x.into_iter()).sum::(), (0..23).map(|x| x*2).sum::()); + } +} +