Initial commit

master
Avril 4 years ago
commit f043a949c5
Signed by: flanchan
GPG Key ID: 284488987C31F630

3
.gitignore vendored

@ -0,0 +1,3 @@
/target
Cargo.lock
*~

@ -0,0 +1,9 @@
[package]
name = "stack-vec"
version = "0.1.0"
authors = ["Avril <flanchan@cumallover.me>"]
edition = "2018"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]

@ -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<T>`, 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::<i32>()).sum::<i32>(), (0..12).map(|x| x*x).sum::<i32>());
/// ```
/// # 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::<i32>(), 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<T>([::std::mem::MaybeUninit<T>; $n], usize);
impl<T> $name<T>
{
#![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<U: AsRef<[T]>>(&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<T> 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<U: AsRef<[T]>>(&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<T>] 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<T>] 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<T>]
{
&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<T>]
{
&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<T>]
{
&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<T>]
{
&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<T>; $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<T>; $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<T> ::std::ops::Drop for $name<T>
{
fn drop(&mut self)
{
if std::mem::needs_drop::<T>() {
for init in &mut self.0[..self.1]
{
unsafe {
drop(std::mem::replace(init, std::mem::MaybeUninit::uninit()).assume_init());
}
}
}
}
}
impl<T> ::std::ops::DerefMut for $name<T>
{
#[inline] fn deref_mut(&mut self) -> &mut Self::Target
{
self.as_mut_slice()
}
}
impl<T> ::std::ops::Deref for $name<T>
{
type Target = [T];
#[inline] fn deref(&self) -> &Self::Target
{
self.as_slice()
}
}
impl<T> ::std::convert::AsRef<[T]> for $name<T>
{
#[inline] fn as_ref(&self) -> &[T]
{
self.as_slice()
}
}
impl<T> ::std::convert::AsMut<[T]> for $name<T>
{
#[inline] fn as_mut(&mut self) -> &mut [T]
{
self.as_mut_slice()
}
}
impl<T> ::std::borrow::Borrow<[T]> for $name<T>
{
#[inline] fn borrow(&self) -> &[T]
{
self.as_slice()
}
}
impl<T> ::std::borrow::BorrowMut<[T]> for $name<T>
{
#[inline] fn borrow_mut(&mut self) -> &mut [T]
{
self.as_mut_slice()
}
}
impl<T> ::std::fmt::Debug for $name<T>
where T: ::std::fmt::Debug
{
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result
{
write!(f, "{:?}", self.as_slice())
}
}
impl<T> ::std::cmp::Eq for $name<T>
where T: ::std::cmp::Eq{}
impl<T,U> ::std::cmp::PartialEq<U> for $name<T>
where T: ::std::cmp::PartialEq,
U: AsRef<[T]>
{
#[inline]
fn eq(&self, other: &U) -> bool
{
self.as_slice() == other.as_ref()
}
}
impl<T> ::std::cmp::Ord for $name<T>
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<T, U> ::std::cmp::PartialOrd<U> for $name<T>
where T: ::std::cmp::PartialOrd,
U: AsRef<[T]>
{
#[inline]
fn partial_cmp(&self, other: &U) -> Option<std::cmp::Ordering> {
std::cmp::PartialOrd::partial_cmp(self.as_slice(), other.as_ref())
}
}
impl<T,I: ::std::slice::SliceIndex<[T]>> std::ops::Index<I> for $name<T>
{
type Output = I::Output;
#[inline]
fn index(&self, index: I) -> &Self::Output {
std::ops::Index::index(self.as_slice(), index)
}
}
impl<T,I: ::std::slice::SliceIndex<[T]>> std::ops::IndexMut<I> for $name<T>
{
#[inline]
fn index_mut(&mut self, index: I) -> &mut Self::Output {
std::ops::IndexMut::index_mut(self.as_mut_slice(), index)
}
}
impl<T> ::std::clone::Clone for $name<T>
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<T> ::std::convert::From<$name<T>> for ::std::vec::Vec<T>
{
#[inline] fn from(from: $name<T>) -> Self
{
from.into_iter().collect()
}
}
impl<T> std::default::Default for $name<T>
{
#[inline]
fn default() -> Self
{
Self::new()
}
}
impl<T> ::std::iter::IntoIterator for $name<T>
{
type Item= T;
type IntoIter = $into_iter_name<T>;
fn into_iter(self) -> Self::IntoIter
{
$into_iter_name(self, 0)
}
}
impl ::std::io::Write for $name<u8>
{
fn write(&mut self, buf: &[u8]) -> ::std::io::Result<usize>
{
Ok(self.extend_from_slice_copy(buf))
}
#[inline]
fn write_vectored(&mut self, bufs: &[::std::io::IoSlice<'_>]) -> ::std::io::Result<usize> {
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<T> ::std::convert::From<[T; $n]> for $name<T>
{
#[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<T> as *mut T, $n);
}
this.1=$n;
std::mem::forget(from);
this
}
}
impl<T> ::std::iter::FromIterator<T> for $name<T>
{
fn from_iter<I: IntoIterator<Item=T>>(iter: I) -> Self
{
let mut output = Self::new();
for item in iter
{
output.push(item);
}
output
}
}
pub struct $into_iter_name<T>($name<T>, usize);
impl<T> $into_iter_name<T>
{
#![allow(dead_code)]
pub fn rest(&self) -> &[std::mem::MaybeUninit<T>]
{
&self.0.init_buffer()[self.1..]
}
pub fn rest_mut(&mut self) -> &mut [std::mem::MaybeUninit<T>]
{
&mut self.0.init_buffer_mut()[self.1..]
}
}
impl<T> std::iter::Iterator for $into_iter_name<T>
{
type Item = T;
fn next(&mut self) -> Option<Self::Item>
{
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<usize>)
{
(self.0.len(), Some(self.0.len()))
}
}
impl<T> std::iter::ExactSizeIterator for $into_iter_name<T>{}
impl<T> std::iter::FusedIterator for $into_iter_name<T>{}
impl<T> std::ops::Drop for $into_iter_name<T>
{
fn drop(&mut self)
{
if std::mem::needs_drop::<T>() {
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<i32> = 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::<String>().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::<usize>(), 7);
assert_eq!(sv.iter().flat_map(|x| x.iter()).sum::<usize>(), 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::<usize>(), 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::<Vec<_>>(), sv.into_iter().collect::<Vec<_>>());
}
#[test]
fn from_iterator()
{
let sv: StackVec256<_> = vec![1,2,3,4,5,6].into_iter().collect();
assert_eq!(sv.into_iter().sum::<i32>(), 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::<i32>(), 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::<i32>(), (0..23).map(|x| x*2).sum::<i32>());
}
}
Loading…
Cancel
Save