Add ArrayVec::splice and TinyVec::splice (#85)

* Add ArrayVec::splice and TinyVec::splice

Added for closer API parity with std::Vec

* Fix ArrayVec::splice example typo

* Removed FusedIterator bound from splice

This bound could've caused confusing error messages, and was
inconsistent with the Vec API. splice now uses fuse itself to ensure
consistency. Vec::splice consumes the whole iterator at once, so it
essentially has the same behavior, but this implementation gradually
consumes the iterator as elements are drained, so this fuse is necessary
to keep the behavior the same.

* Reserve additional capacity in TinyVecSplice

Used TinyVec::reserve to pre-allocate space for elements being spliced
into the TinyVec after the splicing iterator is dropped. Used the lower
bound like Vec's splice does.

* Run rustfmt
This commit is contained in:
Benjamin Scherer
2020-07-18 00:22:59 -06:00
committed by GitHub
parent af665296b5
commit 04f65e50cf
4 changed files with 714 additions and 31 deletions
+183 -7
View File
@@ -147,9 +147,11 @@ impl<A: Array> ArrayVec<A> {
#[inline]
pub fn append(&mut self, other: &mut Self) {
let new_len = self.len() + other.len();
assert!(new_len <= A::CAPACITY,
"ArrayVec::append> total length {} exceeds capacity {}!",
new_len, A::CAPACITY
assert!(
new_len <= A::CAPACITY,
"ArrayVec::append> total length {} exceeds capacity {}!",
new_len,
A::CAPACITY
);
for item in other.drain(..) {
@@ -174,7 +176,10 @@ impl<A: Array> ArrayVec<A> {
/// assert_eq!(av3, &[7, 8, 9][..]);
/// ```
#[inline]
pub fn try_append<'other>(&mut self, other: &'other mut Self) -> Option<&'other mut Self> {
pub fn try_append<'other>(
&mut self,
other: &'other mut Self,
) -> Option<&'other mut Self> {
let new_len = self.len() + other.len();
if new_len > A::CAPACITY {
return Some(other);
@@ -403,8 +408,8 @@ impl<A: Array> ArrayVec<A> {
assert!(x.is_none(), "ArrayVec::insert> capacity overflow!");
}
/// Tries to insert an item at the position given, moving all following elements +1
/// index.
/// Tries to insert an item at the position given, moving all following
/// elements +1 index.
/// Returns back the element if the capacity is exhausted,
/// otherwise returns None.
///
@@ -730,6 +735,74 @@ impl<A: Array> ArrayVec<A> {
new
}
/// Creates a splicing iterator that removes the specified range in the
/// vector, yields the removed items, and replaces them with elements from
/// the provided iterator.
///
/// `splice` fuses the provided iterator, so elements after the first `None`
/// are ignored.
///
/// ## Panics
/// * If the start is greater than the end.
/// * If the end is past the edge of the vec.
/// * If the provided iterator panics.
/// * If the new length would overflow the capacity of the array. Because
/// `ArrayVecSplice` adds elements to this vec in its destructor when
/// necessary, this panic would occur when it is dropped.
///
/// ## Example
/// ```rust
/// use tinyvec::*;
/// let mut av = array_vec!([i32; 4] => 1, 2, 3);
/// let av2: ArrayVec<[i32; 4]> = av.splice(1.., 4..=6).collect();
/// assert_eq!(av.as_slice(), &[1, 4, 5, 6][..]);
/// assert_eq!(av2.as_slice(), &[2, 3][..]);
///
/// av.splice(.., None);
/// assert_eq!(av.as_slice(), &[]);
/// ```
#[inline]
pub fn splice<R, I>(
&mut self,
range: R,
replacement: I,
) -> ArrayVecSplice<'_, A, core::iter::Fuse<I::IntoIter>>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = A::Item>,
{
use core::ops::Bound;
let start = match range.start_bound() {
Bound::Included(x) => *x,
Bound::Excluded(x) => x + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(x) => x + 1,
Bound::Excluded(x) => *x,
Bound::Unbounded => self.len(),
};
assert!(
start <= end,
"ArrayVec::splice> Illegal range, {} to {}",
start,
end
);
assert!(
end <= self.len(),
"ArrayVec::splice> Range ends at {} but length is only {}!",
end,
self.len()
);
ArrayVecSplice {
removal_start: start,
removal_end: end,
parent: self,
replacement: replacement.into_iter().fuse(),
}
}
/// Remove an element, swapping the end of the vec into its place.
///
/// ## Panics
@@ -905,6 +978,110 @@ impl<'p, A: Array> Drop for ArrayVecDrain<'p, A> {
}
}
/// Splicing iterator for `ArrayVec`
/// See [`ArrayVec::splice`](ArrayVec::<A>::splice)
pub struct ArrayVecSplice<'p, A: Array, I: Iterator<Item = A::Item>> {
parent: &'p mut ArrayVec<A>,
removal_start: usize,
removal_end: usize,
replacement: I,
}
impl<'p, A: Array, I: Iterator<Item = A::Item>> Iterator
for ArrayVecSplice<'p, A, I>
{
type Item = A::Item;
fn next(&mut self) -> Option<A::Item> {
if self.removal_start < self.removal_end {
match self.replacement.next() {
Some(replacement) => {
let removed = core::mem::replace(
&mut self.parent[self.removal_start],
replacement,
);
self.removal_start += 1;
Some(removed)
}
None => {
let removed = self.parent.remove(self.removal_start);
self.removal_end -= 1;
Some(removed)
}
}
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'p, A, I> ExactSizeIterator for ArrayVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item>,
{
#[inline]
fn len(&self) -> usize {
self.removal_end - self.removal_start
}
}
impl<'p, A, I> FusedIterator for ArrayVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item>,
{
}
impl<'p, A, I> DoubleEndedIterator for ArrayVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item> + DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<A::Item> {
if self.removal_start < self.removal_end {
match self.replacement.next_back() {
Some(replacement) => {
let removed = core::mem::replace(
&mut self.parent[self.removal_end - 1],
replacement,
);
self.removal_end -= 1;
Some(removed)
}
None => {
let removed = self.parent.remove(self.removal_end - 1);
self.removal_end -= 1;
Some(removed)
}
}
} else {
None
}
}
}
impl<'p, A: Array, I: Iterator<Item = A::Item>> Drop
for ArrayVecSplice<'p, A, I>
{
fn drop(&mut self) {
for _ in self.by_ref() {}
// FIXME: reserve lower bound of size_hint
for replacement in self.replacement.by_ref() {
self.parent.insert(self.removal_end, replacement);
self.removal_end += 1;
}
}
}
impl<A: Array> AsMut<[A::Item]> for ArrayVec<A> {
#[inline(always)]
#[must_use]
@@ -1335,4 +1512,3 @@ impl<A: Array> ArrayVec<A> {
self.drain_to_vec_and_reserve(0)
}
}
+198 -22
View File
@@ -161,11 +161,12 @@ impl<A: Array> TinyVec<A> {
/// assert!(tv.is_inline());
/// ```
pub fn shrink_to_fit(&mut self)
where A: Default,
where
A: Default,
{
let vec = match self {
TinyVec::Inline(_) => return,
TinyVec::Heap(h) => h,
TinyVec::Heap(h) => h,
};
if vec.len() > A::CAPACITY {
@@ -191,7 +192,7 @@ impl<A: Array> TinyVec<A> {
#[allow(clippy::missing_inline_in_public_items)]
pub fn move_to_the_heap(&mut self) {
let arr = match self {
TinyVec::Heap(_) => return,
TinyVec::Heap(_) => return,
TinyVec::Inline(a) => a,
};
@@ -211,10 +212,10 @@ impl<A: Array> TinyVec<A> {
/// ```
pub fn move_to_the_heap_and_reserve(&mut self, n: usize) {
let arr = match self {
TinyVec::Heap(h) => return h.reserve(n),
TinyVec::Heap(h) => return h.reserve(n),
TinyVec::Inline(a) => a,
};
let v = arr.drain_to_vec_and_reserve(n);
*self = TinyVec::Heap(v);
}
@@ -231,7 +232,7 @@ impl<A: Array> TinyVec<A> {
/// ```
pub fn reserve(&mut self, n: usize) {
let arr = match self {
TinyVec::Heap(h) => return h.reserve(n),
TinyVec::Heap(h) => return h.reserve(n),
TinyVec::Inline(a) => a,
};
@@ -250,7 +251,7 @@ impl<A: Array> TinyVec<A> {
/// From [Vec::reserve_exact](https://doc.rust-lang.org/std/vec/struct.Vec.html#method.reserve_exact)
/// ```text
/// Note that the allocator may give the collection more space than it requests.
/// Therefore, capacity can not be relied upon to be precisely minimal.
/// Therefore, capacity can not be relied upon to be precisely minimal.
/// Prefer reserve if future insertions are expected.
/// ```
/// ```rust
@@ -263,7 +264,7 @@ impl<A: Array> TinyVec<A> {
/// ```
pub fn reserve_exact(&mut self, n: usize) {
let arr = match self {
TinyVec::Heap(h) => return h.reserve_exact(n),
TinyVec::Heap(h) => return h.reserve_exact(n),
TinyVec::Inline(a) => a,
};
@@ -285,7 +286,7 @@ impl<A: Array> TinyVec<A> {
let iter = other.drain(..);
match self {
TinyVec::Heap(h) => h.extend(iter),
TinyVec::Heap(h) => h.extend(iter),
TinyVec::Inline(a) => a.extend(iter),
}
}
@@ -455,7 +456,7 @@ impl<A: Array> TinyVec<A> {
self.reserve(sli.len());
match self {
TinyVec::Inline(a) => a.extend_from_slice(sli),
TinyVec::Heap(h) => h.extend_from_slice(sli),
TinyVec::Heap(h) => h.extend_from_slice(sli),
}
}
@@ -505,19 +506,22 @@ impl<A: Array> TinyVec<A> {
/// ```
#[inline]
pub fn insert(&mut self, index: usize, item: A::Item) {
assert!(index <= self.len(),
"insertion index (is {}) should be <= len (is {})",
index, self.len()
assert!(
index <= self.len(),
"insertion index (is {}) should be <= len (is {})",
index,
self.len()
);
let arr = match self {
TinyVec::Heap(v) => return v.insert(index, item),
TinyVec::Heap(v) => return v.insert(index, item),
TinyVec::Inline(a) => a,
};
if let Some(x) = arr.try_insert(index, item) {
let mut v = Vec::with_capacity(arr.len() * 2);
let mut it = arr.iter_mut().map(|r| core::mem::replace(r, Default::default()));
let mut it =
arr.iter_mut().map(|r| core::mem::replace(r, Default::default()));
v.extend(it.by_ref().take(index));
v.push(x);
v.extend(it);
@@ -576,7 +580,7 @@ impl<A: Array> TinyVec<A> {
#[inline(always)]
pub fn push(&mut self, val: A::Item) {
let arr = match self {
TinyVec::Heap(v) => return v.push(val),
TinyVec::Heap(v) => return v.push(val),
TinyVec::Inline(a) => a,
};
@@ -663,13 +667,13 @@ impl<A: Array> TinyVec<A> {
#[inline]
pub fn resize_with<F: FnMut() -> A::Item>(&mut self, new_len: usize, f: F) {
match new_len.checked_sub(self.len()) {
None => return self.truncate(new_len),
None => return self.truncate(new_len),
Some(n) => self.reserve(n),
}
match self {
TinyVec::Inline(a) => a.resize_with(new_len, f),
TinyVec::Heap(v) => v.resize_with(new_len, f),
TinyVec::Heap(v) => v.resize_with(new_len, f),
}
}
@@ -720,6 +724,71 @@ impl<A: Array> TinyVec<A> {
}
}
/// Creates a splicing iterator that removes the specified range in the
/// vector, yields the removed items, and replaces them with elements from
/// the provided iterator.
///
/// `splice` fuses the provided iterator, so elements after the first `None`
/// are ignored.
///
/// ## Panics
/// * If the start is greater than the end.
/// * If the end is past the edge of the vec.
/// * If the provided iterator panics.
///
/// ## Example
/// ```rust
/// use tinyvec::*;
/// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3);
/// let tv2: TinyVec<[i32; 4]> = tv.splice(1.., 4..=6).collect();
/// assert_eq!(tv.as_slice(), &[1, 4, 5, 6][..]);
/// assert_eq!(tv2.as_slice(), &[2, 3][..]);
///
/// tv.splice(.., None);
/// assert_eq!(tv.as_slice(), &[]);
/// ```
#[inline]
pub fn splice<R, I>(
&mut self,
range: R,
replacement: I,
) -> TinyVecSplice<'_, A, core::iter::Fuse<I::IntoIter>>
where
R: RangeBounds<usize>,
I: IntoIterator<Item = A::Item>,
{
use core::ops::Bound;
let start = match range.start_bound() {
Bound::Included(x) => *x,
Bound::Excluded(x) => x + 1,
Bound::Unbounded => 0,
};
let end = match range.end_bound() {
Bound::Included(x) => x + 1,
Bound::Excluded(x) => *x,
Bound::Unbounded => self.len(),
};
assert!(
start <= end,
"TinyVec::splice> Illegal range, {} to {}",
start,
end
);
assert!(
end <= self.len(),
"TinyVec::splice> Range ends at {} but length is only {}!",
end,
self.len()
);
TinyVecSplice {
removal_start: start,
removal_end: end,
parent: self,
replacement: replacement.into_iter().fuse(),
}
}
/// Remove an element, swapping the end of the vec into its place.
///
/// ## Panics
@@ -800,6 +869,113 @@ impl<'p, A: Array> Drop for TinyVecDrain<'p, A> {
}
}
/// Splicing iterator for `TinyVec`
/// See [`TinyVec::splice`](TinyVec::<A>::splice)
pub struct TinyVecSplice<'p, A: Array, I: Iterator<Item = A::Item>> {
parent: &'p mut TinyVec<A>,
removal_start: usize,
removal_end: usize,
replacement: I,
}
impl<'p, A, I> Iterator for TinyVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item>,
{
type Item = A::Item;
fn next(&mut self) -> Option<A::Item> {
if self.removal_start < self.removal_end {
match self.replacement.next() {
Some(replacement) => {
let removed = core::mem::replace(
&mut self.parent[self.removal_start],
replacement,
);
self.removal_start += 1;
Some(removed)
}
None => {
let removed = self.parent.remove(self.removal_start);
self.removal_end -= 1;
Some(removed)
}
}
} else {
None
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.len();
(len, Some(len))
}
}
impl<'p, A, I> ExactSizeIterator for TinyVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item>,
{
#[inline]
fn len(&self) -> usize {
self.removal_end - self.removal_start
}
}
impl<'p, A, I> FusedIterator for TinyVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item>,
{
}
impl<'p, A, I> DoubleEndedIterator for TinyVecSplice<'p, A, I>
where
A: Array,
I: Iterator<Item = A::Item> + DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<A::Item> {
if self.removal_start < self.removal_end {
match self.replacement.next_back() {
Some(replacement) => {
let removed = core::mem::replace(
&mut self.parent[self.removal_end - 1],
replacement,
);
self.removal_end -= 1;
Some(removed)
}
None => {
let removed = self.parent.remove(self.removal_end - 1);
self.removal_end -= 1;
Some(removed)
}
}
} else {
None
}
}
}
impl<'p, A: Array, I: Iterator<Item = A::Item>> Drop
for TinyVecSplice<'p, A, I>
{
fn drop(&mut self) {
for _ in self.by_ref() {}
let (lower_bound, _) = self.replacement.size_hint();
self.parent.reserve(lower_bound);
for replacement in self.replacement.by_ref() {
self.parent.insert(self.removal_end, replacement);
self.removal_end += 1;
}
}
}
impl<A: Array> AsMut<[A::Item]> for TinyVec<A> {
#[inline(always)]
#[must_use]
@@ -839,19 +1015,19 @@ impl<A: Array> Extend<A::Item> for TinyVec<A> {
let (lower_bound, _) = iter.size_hint();
self.reserve(lower_bound);
let a = match self {
let a = match self {
TinyVec::Heap(h) => return h.extend(iter),
TinyVec::Inline(a) => a,
};
let mut iter = a.fill(iter);
let maybe = iter.next();
let surely = match maybe {
Some(x) => x,
None => return,
};
let mut v = a.drain_to_vec_and_reserve(a.len());
v.push(surely);
v.extend(iter);