Add the SliceVec type (#68)

* start of slicevec

* remove todo! because it's not in 1.36

* Update Cargo.toml

* slice vec into iterator

* slicevec drain

* complete last unimplemented

* remove the extra default feature

* spelling

* Update src/slicevec.rs

Co-Authored-By: Joshua Nelson <joshua@yottadb.com>

* docs clarification.

Co-authored-by: Joshua Nelson <joshua@yottadb.com>
This commit is contained in:
Lokathor
2020-04-22 12:31:56 -06:00
committed by GitHub
parent d04abff44c
commit c81bc9f0b1
5 changed files with 1121 additions and 76 deletions
+9 -4
View File
@@ -15,11 +15,11 @@ repository = "https://github.com/Lokathor/tinyvec"
[features]
default = []
# Provide things that utilize the `alloc` crate.
# Provide things that utilize the `alloc` crate, namely `TinyVec`.
alloc = []
# (not part of Vec!) Extra methods to let you grab the slice of memory after the
# "active" portion of an `ArrayVec`.
# "active" portion of an `ArrayVec` or `SliceVec`.
grab_spare_slice = []
# allow use of nightly feature `slice_partition_dedup`,
@@ -30,8 +30,10 @@ nightly_slice_partition_dedup = []
# use const generics for arrays
nightly_const_generics = []
# NOT considered part of the crate's SemVer!!!
# This experimental feature adds `core::fmt::Write` to ArrayVec.
# EXPERIMENTAL: Not part of SemVer. It adds `core::fmt::Write` to `ArrayVec`
# and `SliceVec`. It works on Stable Rust, but Vec normally supports the
# `std::io::Write` trait instead of `core::fmt::Write`, so we're keeping it as
# an experimental impl only for now.
experimental_write_impl = []
[badges]
@@ -41,6 +43,9 @@ travis-ci = { repository = "Lokathor/tinyvec" }
[package.metadata.docs.rs]
all-features = true
[profile.test]
opt-level = 3
[workspace]
members = ["fuzz"]
+70 -67
View File
@@ -287,22 +287,62 @@ impl<A: Array> ArrayVec<A> {
self.set_len(new_len);
}
/// Fill the vector until its capacity has been reached.
///
/// Successively fills unused space in the spare slice of the vector with
/// elements from the iterator. It then returns the remaining iterator
/// without exhausting it. This also allows appending the head of an
/// infinite iterator.
///
/// This is an alternative to `Extend::extend` method for cases where the
/// length of the iterator can not be checked. Since this vector can not
/// reallocate to increase its capacity, it is unclear what to do with
/// remaining elements in the iterator and the iterator itself. The
/// interface also provides no way to communicate this to the caller.
///
/// ## Panics
/// * If the `next` method of the provided iterator panics.
///
/// ## Example
///
/// ```rust
/// # use tinyvec::*;
/// let mut av = array_vec!([i32; 4]);
/// let mut to_inf = av.fill(0..);
/// assert_eq!(&av[..], [0, 1, 2, 3]);
/// assert_eq!(to_inf.next(), Some(4));
/// ```
#[inline]
pub fn fill<I: IntoIterator<Item = A::Item>>(
&mut self,
iter: I,
) -> I::IntoIter {
let mut iter = iter.into_iter();
for element in iter.by_ref().take(self.capacity() - self.len()) {
self.push(element);
}
iter
}
/// Wraps up an array and uses the given length as the initial length.
///
/// If you want to simply use the full array, use `from` instead.
///
/// ## Panics
///
/// * The length specified must be less than or equal to the capacity of the array.
/// * The length specified must be less than or equal to the capacity of the
/// array.
#[inline]
#[must_use]
#[allow(clippy::match_wild_err_arm)]
pub fn from_array_len(data: A, len: usize) -> Self {
match Self::try_from_array_len(data, len) {
Ok(out) => out,
Err(_) => {
panic!("ArrayVec::from_array_len> length {} exceeds capacity {}!", len, A::CAPACITY)
}
Err(_) => panic!(
"ArrayVec::from_array_len> length {} exceeds capacity {}!",
len,
A::CAPACITY
),
}
}
@@ -310,7 +350,7 @@ impl<A: Array> ArrayVec<A> {
/// index.
///
/// ## Panics
/// * If `index` > `len` or
/// * If `index` > `len`
/// * If the capacity is exhausted
///
/// ## Example
@@ -427,16 +467,14 @@ impl<A: Array> ArrayVec<A> {
#[inline]
pub fn remove(&mut self, index: usize) -> A::Item {
let targets: &mut [A::Item] = &mut self.deref_mut()[index..];
let item = replace(&mut targets[0], A::Item::default());
let item = take(&mut targets[0]);
targets.rotate_left(1);
self.len -= 1;
item
}
/// Resize the vec to the new length.
///
/// If it needs to be longer, it's filled with clones of the provided value.
/// If it needs to be shorter, it's truncated.
/// As [`resize_with`](ArrayVec::resize_with)
/// and it clones the value as the closure.
///
/// ## Example
///
@@ -456,16 +494,7 @@ impl<A: Array> ArrayVec<A> {
where
A::Item: Clone,
{
match new_len.checked_sub(self.len) {
None => self.truncate(new_len),
Some(0) => (),
Some(new_elements) => {
for _ in 1..new_elements {
self.push(new_val.clone());
}
self.push(new_val);
}
}
self.resize_with(new_len, || new_val.clone())
}
/// Resize the vec to the new length.
@@ -484,7 +513,10 @@ impl<A: Array> ArrayVec<A> {
///
/// let mut av = array_vec!([i32; 10]);
/// let mut p = 1;
/// av.resize_with(4, || { p *= 2; p });
/// av.resize_with(4, || {
/// p *= 2;
/// p
/// });
/// assert_eq!(&av[..], [2, 4, 8, 16]);
/// ```
#[inline]
@@ -567,49 +599,16 @@ impl<A: Array> ArrayVec<A> {
// just let some other call later on trigger a panic on accident when the
// length is wrong. However, it's a lot easier to catch bugs when things
// are more "fail-fast".
panic!("ArrayVec: set_len overflow!")
panic!(
"ArrayVec::set_len> new length {} exceeds capacity {}",
new_len,
A::CAPACITY
)
} else {
self.len = new_len;
}
}
/// Fill the vector until its capacity has been reached.
///
/// Successively fills unused space in the spare slice of the vector with
/// elements from the iterator. It then returns the remaining iterator
/// without exhausting it. This also allows appending the head of an
/// infinite iterator.
///
/// This is an alternative to `Extend::extend` method for cases where the
/// length of the iterator can not be checked. Since this vector can not
/// reallocate to increase its capacity, it is unclear what to do with
/// remaining elements in the iterator and the iterator itself. The
/// interface also provides no way to communicate this to the caller.
///
/// ## Panics
/// * If the `next` method of the provided iterator panics.
///
/// ## Example
///
/// ```rust
/// # use tinyvec::*;
/// let mut av = array_vec!([i32; 4]);
/// let mut to_inf = av.fill(0..);
/// assert_eq!(&av[..], [0, 1, 2, 3]);
/// assert_eq!(to_inf.next(), Some(4));
/// ```
#[inline]
pub fn fill<I: IntoIterator<Item = A::Item>>(
&mut self,
iter: I,
) -> I::IntoIter {
let mut iter = iter.into_iter();
for element in iter.by_ref().take(self.capacity() - self.len()) {
self.push(element);
}
iter
}
/// Splits the collection at the point given.
///
/// * `[0, at)` stays in this vec
@@ -786,7 +785,7 @@ impl<A: Array> ArrayVec<A> {
}
}
/// Draining iterator for `ArrayVecDrain`
/// Draining iterator for [`ArrayVec`]
///
/// See [`ArrayVec::drain`](ArrayVec::drain)
pub struct ArrayVecDrain<'p, A: Array> {
@@ -808,15 +807,17 @@ impl<'p, A: Array> Iterator for ArrayVecDrain<'p, A> {
}
}
}
impl<'p, A: Array> FusedIterator for ArrayVecDrain<'p, A> { }
impl<'p, A: Array> FusedIterator for ArrayVecDrain<'p, A> {}
impl<'p, A: Array> Drop for ArrayVecDrain<'p, A> {
#[inline]
fn drop(&mut self) {
// Changed because it was moving `self`, it's also more clear and the std does the same
// Changed because it was moving `self`, it's also more clear and the std
// does the same
self.for_each(drop);
// Implementation very similar to [`ArrayVec::remove`](ArrayVec::remove)
let count = self.target_end - self.target_start;
let targets: &mut [A::Item] = &mut self.parent.deref_mut()[self.target_start..];
let targets: &mut [A::Item] =
&mut self.parent.deref_mut()[self.target_start..];
targets.rotate_left(count);
self.parent.len -= count;
}
@@ -902,7 +903,7 @@ impl<A: Array> ArrayVecIterator<A> {
&self.data.as_slice()[self.base..self.len]
}
}
impl<A: Array> FusedIterator for ArrayVecIterator<A> { }
impl<A: Array> FusedIterator for ArrayVecIterator<A> {}
impl<A: Array> Iterator for ArrayVecIterator<A> {
type Item = A::Item;
#[inline]
@@ -942,7 +943,10 @@ impl<A: Array> Iterator for ArrayVecIterator<A> {
}
}
impl<A: Array> Debug for ArrayVecIterator<A> where A::Item: Debug {
impl<A: Array> Debug for ArrayVecIterator<A>
where
A::Item: Debug,
{
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("ArrayVecIterator").field(&self.as_slice()).finish()
@@ -1045,8 +1049,7 @@ where
}
#[cfg(feature = "experimental_write_impl")]
impl<A: Array<Item=u8>> core::fmt::Write for ArrayVec<A>
{
impl<A: Array<Item = u8>> core::fmt::Write for ArrayVec<A> {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
let my_len = self.len();
let str_len = s.as_bytes().len();
+15 -5
View File
@@ -28,6 +28,11 @@
//! * [`ArrayVec`](ArrayVec) is an array-backed vec-like structure with a fixed
//! capacity. If you try to grow the length past the array's capacity it will
//! error or panic (depending on the method used).
//! * [`SliceVec`](SliceVec) is similar, but instead of the vec having an owned
//! array, it holds onto a unique borrow of a slice. This means that it's far
//! cheaper to pass around (since you don't move the whole array), but it can
//! be trickier to thread a lifetime marker everywhere through all your
//! function signatures.
//! * (`alloc` feature) [`TinyVec`](TinyVec) is an enum that's either an
//! "Inline" `ArrayVec` or a "Heap" `Vec`. If it's Inline and you try to grow
//! the `ArrayVec` beyond its array capacity it will quietly transition into
@@ -42,22 +47,24 @@
//! `serde` compatibility).
//! 3) The intended API is that, _as much as possible_, these types are
//! essentially a "drop-in" replacement for the standard [`Vec`](Vec::<T>)
//! type.
//! type. Because of the "no `unsafe`" rule this can't be done perfectly.
//! * Stable `Vec` methods that the vecs here also have should be the same
//! general signature.
//! * Unstable `Vec` methods are sometimes provided via a crate feature, but
//! if so they also require a Nightly compiler.
//! * Some methods are provided that _are not_ part of the `Vec` type, such
//! as additional constructor methods. In this case, the names are rather
//! long and whimsical in the hopes that they don't clash with any
//! possible future methods of `Vec`.
//! long and whimsical in the hopes that they don't clash with any possible
//! future methods of `Vec`.
//! * If, in the future, `Vec` stabilizes a method that clashes with an
//! existing extra method here then we'll simply be forced to release a
//! 2.y.z version. Not the end of the world.
//! * Some methods of `Vec` are simply inappropriate and will not be
//! implemented here. For example, `ArrayVec` cannot possibly implement
//! [`from_raw_parts`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts).
//! implemented here. For example, this crate cannot possibly implement
//! [`from_raw_parts`](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.from_raw_parts)
//! because it cannot call `unsafe` methods.
#[allow(unused_imports)]
use core::{
borrow::{Borrow, BorrowMut},
cmp::PartialEq,
@@ -84,6 +91,9 @@ pub use array::*;
mod arrayvec;
pub use arrayvec::*;
mod slicevec;
pub use slicevec::*;
#[cfg(feature = "alloc")]
mod tinyvec;
#[cfg(feature = "alloc")]
+1025
View File
File diff suppressed because it is too large Load Diff
+2
View File
@@ -1,3 +1,5 @@
#![cfg(feature = "alloc")]
#![allow(bad_style)]
#![allow(clippy::redundant_clone)]