From 5bb7c7585bea4b57abb16ab93a2e5338835fc2ae Mon Sep 17 00:00:00 2001 From: Lokathor Date: Fri, 3 Jul 2020 10:56:45 -0600 Subject: [PATCH] Closes https://github.com/Lokathor/tinyvec/issues/75 (#77) * Closes https://github.com/Lokathor/tinyvec/issues/75 * This is a breaking change to the macro * benchmarks fixes. * slim down to just `take` --- Cargo.toml | 7 +- README.md | 4 +- benches/macros.rs | 28 +-- src/arrayset.rs | 452 ++++++++++++++++++++++++---------------------- src/arrayvec.rs | 47 +++-- src/lib.rs | 4 +- src/slicevec.rs | 4 +- src/tinyvec.rs | 69 ++++--- tests/arrayvec.rs | 10 +- tests/tinyvec.rs | 3 +- 10 files changed, 322 insertions(+), 306 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1201bc3..f4fbe8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "tinyvec" description = "Just, really the littlest Vec you could need. So smol." -version = "0.3.4-alpha.0" +version = "0.4.0" authors = ["Lokathor "] edition = "2018" license = "Zlib" @@ -36,6 +36,11 @@ nightly_const_generics = [] # an experimental impl only for now. experimental_write_impl = [] +# EXPERIMENTAL: Not part of SemVer. This adds an "ArraySet" type which is +# an array backed set type for situations where you need a set of a known +# small size without allocation. +experimental_array_set = [] + [badges] appveyor = { repository = "Lokathor/tinyvec" } travis-ci = { repository = "Lokathor/tinyvec" } diff --git a/README.md b/README.md index fbd5d5a..9c3e5b3 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![License:Zlib](https://img.shields.io/badge/License-Zlib-brightgreen.svg)](https://opensource.org/licenses/Zlib) ![Minimum Rust Version](https://img.shields.io/badge/Min%20Rust-1.36-green.svg) -[![travis.ci](https://travis-ci.org/Lokathor/tinyvec.svg?branch=master)](https://travis-ci.org/Lokathor/tinyvec) -[![AppVeyor](https://ci.appveyor.com/api/projects/status/wfnu1tyudka6jbk1/branch/master?svg=true)](https://ci.appveyor.com/project/Lokathor/tinyvec/branch/master) +[![travis.ci](https://travis-ci.org/Lokathor/tinyvec.svg?branch=main)](https://travis-ci.org/Lokathor/tinyvec) +[![AppVeyor](https://ci.appveyor.com/api/projects/status/wfnu1tyudka6jbk1/branch/main?svg=true)](https://ci.appveyor.com/project/Lokathor/tinyvec/branch/main) [![crates.io](https://img.shields.io/crates/v/tinyvec.svg)](https://crates.io/crates/tinyvec) [![docs.rs](https://docs.rs/tinyvec/badge.svg)](https://docs.rs/tinyvec/) diff --git a/benches/macros.rs b/benches/macros.rs index 4d5ffdf..e41a2d2 100644 --- a/benches/macros.rs +++ b/benches/macros.rs @@ -10,37 +10,41 @@ fn bench_tinyvec_macro(c: &mut Criterion) { }); g.bench_function("16 of 32", |b| { - b.iter(|| - tiny_vec!([u8; 32], + b.iter(|| { + tiny_vec!([u8; 32]=> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - )); + ) + }); }); g.bench_function("32 of 32", |b| { - b.iter(|| - tiny_vec!([u8; 32], + b.iter(|| { + tiny_vec!([u8; 32]=> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, - )); + ) + }); }); g.bench_function("33 of 32", |b| { - b.iter(|| - tiny_vec!([u8; 32], + b.iter(|| { + tiny_vec!([u8; 32]=> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, - )); + ) + }); }); g.bench_function("64 of 32", |b| { - b.iter(|| - tiny_vec!([u8; 32], + b.iter(|| { + tiny_vec!([u8; 32]=> 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - )); + ) + }); }); } diff --git a/src/arrayset.rs b/src/arrayset.rs index 130bfab..bee59fe 100644 --- a/src/arrayset.rs +++ b/src/arrayset.rs @@ -1,8 +1,14 @@ -use core::borrow::Borrow; -use core::fmt; -use core::mem::swap; -use core::ops::{AddAssign, SubAssign}; +#![cfg(feature = "experimental_array_set")] + +// This was contributed by user `dhardy`! Big thanks. + use super::Array; +use core::{ + borrow::Borrow, + fmt, + mem::swap, + ops::{AddAssign, SubAssign}, +}; /// Error resulting from attempting to insert into a full array #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -11,9 +17,9 @@ pub struct InsertError; // TODO(when std): impl std::error::Error for InsertError {} impl fmt::Display for InsertError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ArraySet: insertion failed") - } + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "ArraySet: insertion failed") + } } /// An array-backed set @@ -26,266 +32,272 @@ impl fmt::Display for InsertError { /// Due to restrictions, `L` may be only `u8` or `u16`. #[derive(Clone, Debug, Default)] pub struct ArraySet { - arr: A, - len: L, + arr: A, + len: L, } impl> ArraySet { - /// Constructs a new, empty, set - #[inline] - pub fn new() -> Self { - ArraySet { - arr: Default::default(), - len: 0.into(), - } - } + /// Constructs a new, empty, set + #[inline] + pub fn new() -> Self { + ArraySet { arr: Default::default(), len: 0.into() } + } } impl> ArraySet { - /// Constructs a new set from given inputs - /// - /// Panics if `len> arr.len()`. - #[inline] - pub fn from(arr: A, len: L) -> Self { - if len.into() > A::CAPACITY { - panic!("ArraySet::from(array, len): len > array.len()"); - } - ArraySet { arr, len } + /// Constructs a new set from given inputs + /// + /// Panics if `len> arr.len()`. + #[inline] + pub fn from(arr: A, len: L) -> Self { + if len.into() > A::CAPACITY { + panic!("ArraySet::from(array, len): len > array.len()"); } + ArraySet { arr, len } + } } impl ArraySet where - L: Copy + PartialEq + From + Into, + L: Copy + PartialEq + From + Into, { - /// Returns the fixed capacity of the set - #[inline] - pub fn capacity(&self) -> usize { - A::CAPACITY - } - - /// Returns the number of elements in the set - #[inline] - pub fn len(&self) -> usize { - self.len.into() - } - - /// Returns true when the set contains no elements - #[inline] - pub fn is_empty(&self) -> bool { - self.len == 0.into() - } - - /// Removes all elements - #[inline] - pub fn clear(&mut self) { - self.len = 0.into(); - } - - /// Iterate over all contents - #[inline] - pub fn iter(&self) -> Iter { - Iter { a: self.arr.as_slice(), i: 0 } - } + /// Returns the fixed capacity of the set + #[inline] + pub fn capacity(&self) -> usize { + A::CAPACITY + } + + /// Returns the number of elements in the set + #[inline] + pub fn len(&self) -> usize { + self.len.into() + } + + /// Returns true when the set contains no elements + #[inline] + pub fn is_empty(&self) -> bool { + self.len == 0.into() + } + + /// Removes all elements + #[inline] + pub fn clear(&mut self) { + self.len = 0.into(); + } + + /// Iterate over all contents + #[inline] + pub fn iter(&self) -> Iter { + Iter { a: self.arr.as_slice(), i: 0 } + } } impl ArraySet where - L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, + L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, { - /// Check whether the set contains `elt` - #[inline] - pub fn contains(&self, elt: &Q) -> bool where A::Item: Borrow { - self.get(elt).is_some() - } + /// Check whether the set contains `elt` + #[inline] + pub fn contains(&self, elt: &Q) -> bool + where + A::Item: Borrow, + { + self.get(elt).is_some() + } - /// Get a reference to a contained item matching `elt` - pub fn get(&self, elt: &Q) -> Option<&A::Item> where - A::Item: Borrow { - let len: usize = self.len.into(); - let arr = self.arr.as_slice(); - for i in 0..len { - if arr[i].borrow() == elt { - return Some(&arr[i]); - } - } - None + /// Get a reference to a contained item matching `elt` + pub fn get(&self, elt: &Q) -> Option<&A::Item> + where + A::Item: Borrow, + { + let len: usize = self.len.into(); + let arr = self.arr.as_slice(); + for i in 0..len { + if arr[i].borrow() == elt { + return Some(&arr[i]); + } } + None + } - /// Remove an item matching `elt`, if any - pub fn remove(&mut self, elt: &Q) -> Option where - A::Item: Borrow { - let len: usize = self.len.into(); - let arr = self.arr.as_slice_mut(); - for i in 0..len { - if arr[i].borrow() == elt { - let l1 = len - 1; - if i < l1 { - arr.swap(i, l1); - } - self.len -= L::from(1); - let mut r = Default::default(); - swap(&mut arr[l1], &mut r); - return Some(r); - } + /// Remove an item matching `elt`, if any + pub fn remove(&mut self, elt: &Q) -> Option + where + A::Item: Borrow, + { + let len: usize = self.len.into(); + let arr = self.arr.as_slice_mut(); + for i in 0..len { + if arr[i].borrow() == elt { + let l1 = len - 1; + if i < l1 { + arr.swap(i, l1); } - None + self.len -= L::from(1); + return take(&mut arr[l1]); + } } - - /// Remove any items for which `f(item) == false` - pub fn retain(&mut self, mut f: F) where - F: FnMut(&A::Item) -> bool { - let mut len = self.len; - let arr = self.arr.as_slice_mut(); - let mut i = 0; - while i < len.into() { - if !f(&arr[i]) { - len -= L::from(1); - if i < len.into() { - arr.swap(i, len.into()); - } - } else { - i += 1; - } + None + } + + /// Remove any items for which `f(item) == false` + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&A::Item) -> bool, + { + let mut len = self.len; + let arr = self.arr.as_slice_mut(); + let mut i = 0; + while i < len.into() { + if !f(&arr[i]) { + len -= L::from(1); + if i < len.into() { + arr.swap(i, len.into()); } - self.len = len; + } else { + i += 1; + } } + self.len = len; + } } impl ArraySet where - A::Item: Eq, - L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, + A::Item: Eq, + L: Copy + PartialOrd + AddAssign + SubAssign + From + Into, { - /// Insert an item - /// - /// Due to the fixed size of the backing array, insertion may fail. - #[inline] - pub fn insert(&mut self, elt: A::Item) -> Result { - if self.contains(&elt) { - return Ok(false); - } - - let len = self.len.into(); - let arr = self.arr.as_slice_mut(); - if len >= arr.len() { - return Err(InsertError); - } - arr[len] = elt; - self.len += L::from(1); - Ok(true) + /// Insert an item + /// + /// Due to the fixed size of the backing array, insertion may fail. + #[inline] + pub fn insert(&mut self, elt: A::Item) -> Result { + if self.contains(&elt) { + return Ok(false); } - - /* Hits borrow checker - pub fn get_or_insert(&mut self, elt: A::Item) -> Result<&A::Item, InsertError> { - if let Some(r) = self.get(&elt) { - return Ok(r); - } - self.insert(elt)?; - let len: usize = self.len.into(); - Ok(&self.arr.as_slice()[len - 1]) + + let len = self.len.into(); + let arr = self.arr.as_slice_mut(); + if len >= arr.len() { + return Err(InsertError); } - */ - - /// Replace an item matching `elt` with `elt`, or insert `elt` - /// - /// Returns the replaced item, if any. Fails when there is no matching item - /// and the backing array is full, preventing insertion. - pub fn replace(&mut self, mut elt: A::Item) -> Result, InsertError> { - let len: usize = self.len.into(); - let arr = self.arr.as_slice_mut(); - for i in 0..len { - if arr[i] == elt { - swap(&mut arr[i], &mut elt); - return Ok(Some(elt)); - } - } - - if len >= arr.len() { - return Err(InsertError); - } - arr[len] = elt; - self.len += L::from(1); - Ok(None) + arr[len] = elt; + self.len += L::from(1); + Ok(true) + } + + /* Hits borrow checker + pub fn get_or_insert(&mut self, elt: A::Item) -> Result<&A::Item, InsertError> { + if let Some(r) = self.get(&elt) { + return Ok(r); + } + self.insert(elt)?; + let len: usize = self.len.into(); + Ok(&self.arr.as_slice()[len - 1]) + } + */ + + /// Replace an item matching `elt` with `elt`, or insert `elt` + /// + /// Returns the replaced item, if any. Fails when there is no matching item + /// and the backing array is full, preventing insertion. + pub fn replace( + &mut self, + mut elt: A::Item, + ) -> Result, InsertError> { + let len: usize = self.len.into(); + let arr = self.arr.as_slice_mut(); + for i in 0..len { + if arr[i] == elt { + swap(&mut arr[i], &mut elt); + return Ok(Some(elt)); + } } + + if len >= arr.len() { + return Err(InsertError); + } + arr[len] = elt; + self.len += L::from(1); + Ok(None) + } } /// Type returned by [`ArraySet::iter`] pub struct Iter<'a, T> { - a: &'a [T], - i: usize, + a: &'a [T], + i: usize, } impl<'a, T> ExactSizeIterator for Iter<'a, T> { - #[inline] - fn len(&self) -> usize { - self.a.len() - self.i - } + #[inline] + fn len(&self) -> usize { + self.a.len() - self.i + } } impl<'a, T> Iterator for Iter<'a, T> { - type Item = &'a T; + type Item = &'a T; - #[inline] - fn next(&mut self) -> Option { - if self.i < self.a.len() { - let i = self.i; - self.i += 1; - Some(&self.a[i]) - } else { - None - } + #[inline] + fn next(&mut self) -> Option { + if self.i < self.a.len() { + let i = self.i; + self.i += 1; + Some(&self.a[i]) + } else { + None } + } - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len(); - (len, Some(len)) - } + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } } - #[cfg(test)] mod test { - use super::*; - use core::mem::size_of; - - #[test] - fn test_size() { - assert_eq!(size_of::>(), 8); - } - - #[test] - fn test() { - let mut set: ArraySet<[i8; 7], u8> = ArraySet::new(); - assert_eq!(set.capacity(), 7); - - assert_eq!(set.insert(1), Ok(true)); - assert_eq!(set.insert(5), Ok(true)); - assert_eq!(set.insert(6), Ok(true)); - assert_eq!(set.len(), 3); - - assert_eq!(set.insert(5), Ok(false)); - assert_eq!(set.len(), 3); - - assert_eq!(set.replace(1), Ok(Some(1))); - assert_eq!(set.replace(2), Ok(None)); - assert_eq!(set.len(), 4); - - assert_eq!(set.insert(3), Ok(true)); - assert_eq!(set.insert(4), Ok(true)); - assert_eq!(set.insert(7), Ok(true)); - assert_eq!(set.insert(8), Err(InsertError)); - assert_eq!(set.len(), 7); - - assert_eq!(set.replace(9), Err(InsertError)); - - assert_eq!(set.remove(&3), Some(3)); - assert_eq!(set.len(), 6); - - set.retain(|x| *x == 3 || *x == 6); - assert_eq!(set.len(), 1); - assert!(!set.contains(&3)); - assert!(set.contains(&6)); - } + use super::*; + use core::mem::size_of; + + #[test] + fn test_size() { + assert_eq!(size_of::>(), 8); + } + + #[test] + fn test() { + let mut set: ArraySet<[i8; 7], u8> = ArraySet::new(); + assert_eq!(set.capacity(), 7); + + assert_eq!(set.insert(1), Ok(true)); + assert_eq!(set.insert(5), Ok(true)); + assert_eq!(set.insert(6), Ok(true)); + assert_eq!(set.len(), 3); + + assert_eq!(set.insert(5), Ok(false)); + assert_eq!(set.len(), 3); + + assert_eq!(set.replace(1), Ok(Some(1))); + assert_eq!(set.replace(2), Ok(None)); + assert_eq!(set.len(), 4); + + assert_eq!(set.insert(3), Ok(true)); + assert_eq!(set.insert(4), Ok(true)); + assert_eq!(set.insert(7), Ok(true)); + assert_eq!(set.insert(8), Err(InsertError)); + assert_eq!(set.len(), 7); + + assert_eq!(set.replace(9), Err(InsertError)); + + assert_eq!(set.remove(&3), Some(3)); + assert_eq!(set.len(), 6); + + set.retain(|x| *x == 3 || *x == 6); + assert_eq!(set.len(), 1); + assert!(!set.contains(&3)); + assert!(set.contains(&6)); + } } diff --git a/src/arrayvec.rs b/src/arrayvec.rs index c96e5bc..8c3c859 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -13,7 +13,7 @@ use super::*; /// /// // The backing array type can be specified in the macro call /// let empty_av = array_vec!([u8; 16]); -/// let some_ints = array_vec!([i32; 4], 1, 2, 3); +/// let some_ints = array_vec!([i32; 4] => 1, 2, 3); /// /// // Or left to inference /// let empty_av: ArrayVec<[u8; 10]> = array_vec!(); @@ -21,24 +21,21 @@ use super::*; /// ``` #[macro_export] macro_rules! array_vec { - ($array_type:ty) => { - { - let av: $crate::ArrayVec<$array_type> = Default::default(); - av - } - }; - ($array_type:ty, $($elem:expr),*) => { + ($array_type:ty => $($elem:expr),* $(,)?) => { { let mut av: $crate::ArrayVec<$array_type> = Default::default(); $( av.push($elem); )* av } }; - () => { - array_vec!(_) + ($array_type:ty) => { + $crate::array_vec!($array_type =>) }; ($($elem:expr),*) => { - array_vec!(_, $($elem),*) + $crate::array_vec!(_ => $($elem),*) + }; + () => { + $crate::array_vec!(_) }; } @@ -63,7 +60,7 @@ macro_rules! array_vec { /// to have. /// ```rust /// # use tinyvec::*; -/// let some_ints = array_vec!([i32; 4], 1, 2, 3); +/// let some_ints = array_vec!([i32; 4] => 1, 2, 3); /// assert_eq!(some_ints.len(), 3); /// ``` /// @@ -141,8 +138,8 @@ impl ArrayVec { /// ## Example /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([i32; 10], 1, 2, 3); - /// let mut av2 = array_vec!([i32; 10], 4, 5, 6); + /// let mut av = array_vec!([i32; 10] => 1, 2, 3); + /// let mut av2 = array_vec!([i32; 10] => 4, 5, 6); /// av.append(&mut av2); /// assert_eq!(av, &[1, 2, 3, 4, 5, 6][..]); /// assert_eq!(av2, &[][..]); @@ -216,7 +213,7 @@ impl ArrayVec { /// ## Example /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([i32; 4], 1, 2, 3); + /// let mut av = array_vec!([i32; 4] => 1, 2, 3); /// let av2: ArrayVec<[i32; 4]> = av.drain(1..).collect(); /// assert_eq!(av.as_slice(), &[1][..]); /// assert_eq!(av2.as_slice(), &[2, 3][..]); @@ -356,7 +353,7 @@ impl ArrayVec { /// ## Example /// ```rust /// use tinyvec::*; - /// let mut av = array_vec!([i32; 10], 1, 2, 3); + /// let mut av = array_vec!([i32; 10] => 1, 2, 3); /// av.insert(1, 4); /// assert_eq!(av.as_slice(), &[1, 4, 2, 3]); /// av.insert(4, 5); @@ -406,7 +403,7 @@ impl ArrayVec { /// ## Example /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([i32; 10], 1, 2); + /// let mut av = array_vec!([i32; 10] => 1, 2); /// assert_eq!(av.pop(), Some(2)); /// assert_eq!(av.pop(), Some(1)); /// assert_eq!(av.pop(), None); @@ -441,7 +438,7 @@ impl ArrayVec { #[inline(always)] pub fn push(&mut self, val: A::Item) { if self.len < A::CAPACITY { - replace(&mut self.data.as_slice_mut()[self.len], val); + self.data.as_slice_mut()[self.len] = val; self.len += 1; } else { panic!("ArrayVec::push> capacity overflow!") @@ -460,7 +457,7 @@ impl ArrayVec { /// /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([i32; 4], 1, 2, 3); + /// let mut av = array_vec!([i32; 4] => 1, 2, 3); /// assert_eq!(av.remove(1), 2); /// assert_eq!(&av[..], [1, 3]); /// ``` @@ -481,11 +478,11 @@ impl ArrayVec { /// ```rust /// # use tinyvec::*; /// - /// let mut av = array_vec!([&str; 10], "hello"); + /// let mut av = array_vec!([&str; 10] => "hello"); /// av.resize(3, "world"); /// assert_eq!(&av[..], ["hello", "world", "world"]); /// - /// let mut av = array_vec!([i32; 10], 1, 2, 3, 4); + /// let mut av = array_vec!([i32; 10] => 1, 2, 3, 4); /// av.resize(2, 0); /// assert_eq!(&av[..], [1, 2]); /// ``` @@ -507,7 +504,7 @@ impl ArrayVec { /// ```rust /// # use tinyvec::*; /// - /// let mut av = array_vec!([i32; 10], 1, 2, 3); + /// let mut av = array_vec!([i32; 10] => 1, 2, 3); /// av.resize_with(5, Default::default); /// assert_eq!(&av[..], [1, 2, 3, 0, 0]); /// @@ -542,7 +539,7 @@ impl ArrayVec { /// ```rust /// # use tinyvec::*; /// - /// let mut av = array_vec!([i32; 10], 1, 1, 2, 3, 3, 4); + /// let mut av = array_vec!([i32; 10] => 1, 1, 2, 3, 3, 4); /// av.retain(|&x| x % 2 == 0); /// assert_eq!(&av[..], [2, 4]); /// ``` @@ -621,7 +618,7 @@ impl ArrayVec { /// /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([i32; 4], 1, 2, 3); + /// let mut av = array_vec!([i32; 4] => 1, 2, 3); /// let av2 = av.split_off(1); /// assert_eq!(&av[..], [1]); /// assert_eq!(&av2[..], [2, 3]); @@ -656,7 +653,7 @@ impl ArrayVec { /// ## Example /// ```rust /// # use tinyvec::*; - /// let mut av = array_vec!([&str; 4], "foo", "bar", "quack", "zap"); + /// let mut av = array_vec!([&str; 4] => "foo", "bar", "quack", "zap"); /// /// assert_eq!(av.swap_remove(1), "bar"); /// assert_eq!(&av[..], ["foo", "zap", "quack"]); diff --git a/src/lib.rs b/src/lib.rs index f200109..c27db93 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ #![warn(clippy::must_use_candidate)] #![warn(missing_docs)] -//! Programmers can have a little vec, as a treat. +//! For all those times when you need just a little bit of vec support. //! //! ## What This Is //! @@ -88,7 +88,9 @@ pub extern crate alloc; mod array; pub use array::*; +#[cfg(feature = "experimental_array_set")] mod arrayset; +#[cfg(feature = "experimental_array_set")] pub use arrayset::*; mod arrayvec; diff --git a/src/slicevec.rs b/src/slicevec.rs index afa9d55..7a22ee6 100644 --- a/src/slicevec.rs +++ b/src/slicevec.rs @@ -352,7 +352,7 @@ impl<'s, T> SliceVec<'s, T> { #[inline(always)] pub fn push(&mut self, val: T) { if self.len < self.capacity() { - replace(&mut self.data[self.len], val); + self.data[self.len] = val; self.len += 1; } else { panic!("SliceVec::push> capacity overflow") @@ -448,7 +448,7 @@ impl<'s, T> SliceVec<'s, T> { if needs_drop::() { while self.len() > new_len { self.len -= 1; - replace(&mut self.data[self.len], f()); + self.data[self.len] = f(); } } else { self.len = new_len; diff --git a/src/tinyvec.rs b/src/tinyvec.rs index faf9a66..5bf9e05 100644 --- a/src/tinyvec.rs +++ b/src/tinyvec.rs @@ -17,8 +17,8 @@ use alloc::vec::Vec; /// /// // The backing array type can be specified in the macro call /// let empty_tv = tiny_vec!([u8; 16]); -/// let some_ints = tiny_vec!([i32; 4], 1, 2, 3); -/// let many_ints = tiny_vec!([i32; 4], 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); +/// let some_ints = tiny_vec!([i32; 4] => 1, 2, 3); +/// let many_ints = tiny_vec!([i32; 4] => 1, 2, 3, 4, 5, 6, 7, 8, 9, 10); /// /// // Or left to inference /// let empty_tv: TinyVec<[u8; 16]> = tiny_vec!(); @@ -27,36 +27,30 @@ use alloc::vec::Vec; /// ``` #[macro_export] macro_rules! tiny_vec { - ($array_type:ty) => { + ($array_type:ty => $($elem:expr),* $(,)?) => { { - let mut tv: $crate::TinyVec<$array_type> = Default::default(); - tv - } - }; - ($array_type:ty, $($elem:expr),* $(,)?) => { - { - // Note(Lokathor): This goofy looking thing will count the number of - // `$elem` entries we were given. We can't spit out the "+1"s on their - // own, we need to use `$elem` in the repetition-expansion somehow. - // However, we also can't assume it's `Copy` data, so we must use `$elem` - // only once "for real" in the expansion as a whole. To achieve this, we - // can `stringify!` each element in an inner block, then have the block - // return a 1. The stringification is a compile time thing, it won't - // actually move any values. + // https://github.com/rust-lang/lang-team/issues/28 const INVOKED_ELEM_COUNT: usize = 0 $( + { let _ = stringify!($elem); 1 })*; // If we have more `$elem` than the `CAPACITY` we will simply go directly // to constructing on the heap. match $crate::TinyVec::constructor_for_capacity(INVOKED_ELEM_COUNT) { - $crate::TinyVecConstructor::Inline(f) => f($crate::array_vec!($array_type, $($elem),*)), - $crate::TinyVecConstructor::Heap(f) => f(vec!($($elem),*)), + $crate::TinyVecConstructor::Inline(f) => { + f($crate::array_vec!($array_type => $($elem),*)) + } + $crate::TinyVecConstructor::Heap(f) => { + f(vec!($($elem),*)) + } } } }; - () => { - tiny_vec!(_) + ($array_type:ty) => { + $crate::tiny_vec!($array_type =>) }; ($($elem:expr),*) => { - tiny_vec!(_, $($elem),*) + $crate::tiny_vec!(_ => $($elem),*) + }; + () => { + $crate::tiny_vec!(_) }; } @@ -85,7 +79,7 @@ pub enum TinyVecConstructor { /// ```rust /// # use tinyvec::*; /// let empty_tv = tiny_vec!([u8; 16]); -/// let some_ints = tiny_vec!([i32; 4], 1, 2, 3); +/// let some_ints = tiny_vec!([i32; 4] => 1, 2, 3); /// ``` #[derive(Clone)] pub enum TinyVec { @@ -152,7 +146,7 @@ impl TinyVec { for item in arr.drain(..) { v.push(item); } - replace(self, TinyVec::Heap(v)); + *self = TinyVec::Heap(v); } TinyVec::Heap(_) => (), } @@ -274,7 +268,7 @@ impl TinyVec { /// ## Example /// ```rust /// use tinyvec::*; - /// let mut tv = tiny_vec!([i32; 4], 1, 2, 3); + /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// let tv2: TinyVec<[i32; 4]> = tv.drain(1..).collect(); /// assert_eq!(tv.as_slice(), &[1][..]); /// assert_eq!(tv2.as_slice(), &[2, 3][..]); @@ -366,7 +360,7 @@ impl TinyVec { /// ## Example /// ```rust /// use tinyvec::*; - /// let mut tv = tiny_vec!([i32; 10], 1, 2, 3); + /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3); /// tv.insert(1, 4); /// assert_eq!(tv.as_slice(), &[1, 4, 2, 3]); /// tv.insert(4, 5); @@ -456,7 +450,7 @@ impl TinyVec { /// /// ```rust /// use tinyvec::*; - /// let mut tv = tiny_vec!([i32; 4], 1, 2, 3); + /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// assert_eq!(tv.remove(1), 2); /// assert_eq!(tv.as_slice(), &[1, 3][..]); /// ``` @@ -478,11 +472,11 @@ impl TinyVec { /// ```rust /// use tinyvec::*; /// - /// let mut tv = tiny_vec!([&str; 10], "hello"); + /// let mut tv = tiny_vec!([&str; 10] => "hello"); /// tv.resize(3, "world"); /// assert_eq!(tv.as_slice(), &["hello", "world", "world"][..]); /// - /// let mut tv = tiny_vec!([i32; 10], 1, 2, 3, 4); + /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3, 4); /// tv.resize(2, 0); /// assert_eq!(tv.as_slice(), &[1, 2][..]); /// ``` @@ -514,7 +508,7 @@ impl TinyVec { /// ```rust /// use tinyvec::*; /// - /// let mut tv = tiny_vec!([i32; 10], 1, 2, 3); + /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3); /// tv.resize_with(5, Default::default); /// assert_eq!(tv.as_slice(), &[1, 2, 3, 0, 0][..]); /// @@ -541,7 +535,7 @@ impl TinyVec { /// ```rust /// use tinyvec::*; /// - /// let mut tv = tiny_vec!([i32; 10], 1, 2, 3, 4); + /// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3, 4); /// tv.retain(|&x| x % 2 == 0); /// assert_eq!(tv.as_slice(), &[2, 4][..]); /// ``` @@ -565,7 +559,7 @@ impl TinyVec { /// /// ```rust /// use tinyvec::*; - /// let mut tv = tiny_vec!([i32; 4], 1, 2, 3); + /// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3); /// let tv2 = tv.split_off(1); /// assert_eq!(tv.as_slice(), &[1][..]); /// assert_eq!(tv2.as_slice(), &[2, 3][..]); @@ -589,7 +583,7 @@ impl TinyVec { /// ## Example /// ```rust /// use tinyvec::*; - /// let mut tv = tiny_vec!([&str; 4], "foo", "bar", "quack", "zap"); + /// let mut tv = tiny_vec!([&str; 4] => "foo", "bar", "quack", "zap"); /// /// assert_eq!(tv.swap_remove(1), "bar"); /// assert_eq!(tv.as_slice(), &["foo", "zap", "quack"][..]); @@ -640,7 +634,7 @@ pub struct TinyVecDrain<'p, A: Array> { target_index: usize, target_count: usize, } -impl<'p, A: Array> FusedIterator for TinyVecDrain<'p, A> { } +impl<'p, A: Array> FusedIterator for TinyVecDrain<'p, A> {} impl<'p, A: Array> Iterator for TinyVecDrain<'p, A> { type Item = A::Item; #[inline] @@ -778,7 +772,7 @@ impl TinyVecIterator { } } } -impl FusedIterator for TinyVecIterator { } +impl FusedIterator for TinyVecIterator {} impl Iterator for TinyVecIterator { type Item = A::Item; #[inline] @@ -819,7 +813,10 @@ impl Iterator for TinyVecIterator { } } -impl Debug for TinyVecIterator where A::Item: Debug { +impl Debug for TinyVecIterator +where + A::Item: Debug, +{ #[allow(clippy::missing_inline_in_public_items)] fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_tuple("TinyVecIterator").field(&self.as_slice()).finish() diff --git a/tests/arrayvec.rs b/tests/arrayvec.rs index ea63c09..d8c9690 100644 --- a/tests/arrayvec.rs +++ b/tests/arrayvec.rs @@ -10,7 +10,7 @@ fn test_a_vec() { expected.push(2); expected.push(3); - let actual = array_vec!([i32; 4], 1, 2, 3); + let actual = array_vec!(1, 2, 3); assert_eq!(expected, actual); } @@ -88,7 +88,7 @@ fn ArrayVec_formatting() { #[test] fn ArrayVec_iteration() { - let av = array_vec!([i32; 4], 10, 11, 12, 13); + let av = array_vec!([i32; 4] => 10, 11, 12, 13); let mut i = av.into_iter(); assert_eq!(i.next(), Some(10)); @@ -97,7 +97,7 @@ fn ArrayVec_iteration() { assert_eq!(i.next(), Some(13)); assert_eq!(i.next(), None); - let av = array_vec!([i32; 4], 10, 11, 12, 13); + let av = array_vec!([i32; 4] => 10, 11, 12, 13); let mut av2: ArrayVec<[i32; 4]> = av.clone().into_iter().collect(); assert_eq!(av, av2); @@ -113,8 +113,8 @@ fn ArrayVec_iteration() { #[test] fn ArrayVec_append() { - let mut av = array_vec!([i32; 8], 1, 2, 3); - let mut av2 = array_vec!([i32; 8], 4, 5, 6); + let mut av = array_vec!([i32; 8] => 1, 2, 3); + let mut av2 = array_vec!([i32; 8] => 4, 5, 6); // av.append(&mut av2); assert_eq!(av.as_slice(), &[1_i32, 2, 3, 4, 5, 6]); diff --git a/tests/tinyvec.rs b/tests/tinyvec.rs index ce41a69..1007ee2 100644 --- a/tests/tinyvec.rs +++ b/tests/tinyvec.rs @@ -1,5 +1,4 @@ #![cfg(feature = "alloc")] - #![allow(bad_style)] #![allow(clippy::redundant_clone)] @@ -98,5 +97,5 @@ fn TinyVec_from_array() { fn TinyVec_macro_non_copy() { // must use a variable here to avoid macro shenanigans let s = String::new(); - let _: TinyVec<[String; 10]> = tiny_vec!([String; 10], s); + let _: TinyVec<[String; 10]> = tiny_vec!([String; 10] => s); }