mirror of
https://github.com/openharmony/third_party_rust_tinyvec.git
synced 2026-07-19 22:33:42 -04:00
"try_*" functions and "to_vec" for arrayvec (#82)
* change behavior on extend_from_slice, append * preallocation in extend() * append v2 * obviously * fix resize_with * try_functions and to_vec on arrayvec * shrink_to_fit * bit of cleaning * cosmetic changes * use asserts instead of if-panics * I promise, this is the last commit * examples, tests * matches macro exists since rust 1.42 * Update tinyvec.rs * new extend and insert * mem::take is from rust 1.40
This commit is contained in:
+134
-18
@@ -146,11 +146,47 @@ 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
|
||||
);
|
||||
|
||||
for item in other.drain(..) {
|
||||
self.push(item)
|
||||
self.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// Move all values from `other` into this vec.
|
||||
/// If appending would overflow the capacity, Some(other) is returned.
|
||||
/// ## Example
|
||||
/// ```rust
|
||||
/// # use tinyvec::*;
|
||||
/// let mut av = array_vec!([i32; 7] => 1, 2, 3);
|
||||
/// let mut av2 = array_vec!([i32; 7] => 4, 5, 6);
|
||||
/// av.append(&mut av2);
|
||||
/// assert_eq!(av, &[1, 2, 3, 4, 5, 6][..]);
|
||||
/// assert_eq!(av2, &[][..]);
|
||||
///
|
||||
/// let mut av3 = array_vec!([i32; 7] => 7, 8, 9);
|
||||
/// assert!(av.try_append(&mut av3).is_some());
|
||||
/// assert_eq!(av, &[1, 2, 3, 4, 5, 6][..]);
|
||||
/// assert_eq!(av3, &[7, 8, 9][..]);
|
||||
/// ```
|
||||
#[inline]
|
||||
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);
|
||||
}
|
||||
|
||||
for item in other.drain(..) {
|
||||
self.push(item);
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
/// A `*mut` pointer to the backing array.
|
||||
///
|
||||
/// ## Safety
|
||||
@@ -274,13 +310,12 @@ impl<A: Array> ArrayVec<A> {
|
||||
}
|
||||
|
||||
let new_len = self.len + sli.len();
|
||||
if new_len > A::CAPACITY {
|
||||
panic!(
|
||||
"ArrayVec::extend_from_slice> total length {} exceeds capacity {}!",
|
||||
new_len,
|
||||
A::CAPACITY
|
||||
)
|
||||
}
|
||||
assert!(
|
||||
new_len <= A::CAPACITY,
|
||||
"ArrayVec::extend_from_slice> total length {} exceeds capacity {}!",
|
||||
new_len,
|
||||
A::CAPACITY
|
||||
);
|
||||
|
||||
let target = &mut self.data.as_slice_mut()[self.len..new_len];
|
||||
target.clone_from_slice(sli);
|
||||
@@ -364,14 +399,41 @@ impl<A: Array> ArrayVec<A> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn insert(&mut self, index: usize, item: A::Item) {
|
||||
if index > self.len {
|
||||
panic!("ArrayVec::insert> index {} is out of bounds {}", index, self.len);
|
||||
let x = self.try_insert(index, item);
|
||||
assert!(x.is_none(), "ArrayVec::insert> capacity overflow!");
|
||||
}
|
||||
|
||||
/// 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.
|
||||
///
|
||||
/// ## Panics
|
||||
/// * If `index` > `len`
|
||||
///
|
||||
/// ## Example
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut av = array_vec!([&'static str; 4] => "one", "two", "three");
|
||||
/// av.insert(1, "four");
|
||||
/// assert_eq!(av.as_slice(), &["one", "four", "two", "three"]);
|
||||
/// assert_eq!(av.try_insert(4, "five"), Some("five"));
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn try_insert(&mut self, index: usize, item: A::Item) -> Option<A::Item> {
|
||||
assert!(
|
||||
index <= self.len,
|
||||
"ArrayVec::try_insert> index {} is out of bounds {}",
|
||||
index,
|
||||
self.len
|
||||
);
|
||||
|
||||
if let Some(x) = self.try_push(item) {
|
||||
return Some(x);
|
||||
}
|
||||
|
||||
// Try to push the element.
|
||||
self.push(item);
|
||||
// And move it into its place.
|
||||
self.as_mut_slice()[index..].rotate_right(1);
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Checks if the length is 0.
|
||||
@@ -440,12 +502,32 @@ impl<A: Array> ArrayVec<A> {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, val: A::Item) {
|
||||
if self.len < A::CAPACITY {
|
||||
self.data.as_slice_mut()[self.len] = val;
|
||||
self.len += 1;
|
||||
} else {
|
||||
panic!("ArrayVec::push> capacity overflow!")
|
||||
let x = self.try_push(val);
|
||||
assert!(x.is_none(), "ArrayVec::push> capacity overflow!");
|
||||
}
|
||||
|
||||
/// Tries to place an element onto the end of the vec.\
|
||||
/// Returns back the element if the capacity is exhausted,
|
||||
/// otherwise returns None.
|
||||
/// ```rust
|
||||
/// # use tinyvec::*;
|
||||
/// let mut av = array_vec!([i32; 2]);
|
||||
/// assert_eq!(av.as_slice(), []);
|
||||
/// assert_eq!(av.try_push(1), None);
|
||||
/// assert_eq!(&av[..], [1]);
|
||||
/// assert_eq!(av.try_push(2), None);
|
||||
/// assert_eq!(&av[..], [1, 2]);
|
||||
/// assert_eq!(av.try_push(3), Some(3));
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn try_push(&mut self, val: A::Item) -> Option<A::Item> {
|
||||
if self.len == A::CAPACITY {
|
||||
return Some(val);
|
||||
}
|
||||
|
||||
self.data.as_slice_mut()[self.len] = val;
|
||||
self.len += 1;
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Removes the item at `index`, shifting all others down by one index.
|
||||
@@ -1220,3 +1302,37 @@ where
|
||||
write!(f, "]")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
use alloc::vec::Vec;
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl<A: Array> ArrayVec<A> {
|
||||
/// Drains all elements to a Vec, but reserves additional space
|
||||
/// ```
|
||||
/// # use tinyvec::*;
|
||||
/// let mut av = array_vec!([i32; 7] => 1, 2, 3);
|
||||
/// let v = av.drain_to_vec_and_reserve(10);
|
||||
/// assert_eq!(v, &[1, 2, 3]);
|
||||
/// assert_eq!(v.capacity(), 13);
|
||||
/// ```
|
||||
pub fn drain_to_vec_and_reserve(&mut self, n: usize) -> Vec<A::Item> {
|
||||
let cap = n + self.len();
|
||||
let mut v = Vec::with_capacity(cap);
|
||||
v.extend(self.drain(..));
|
||||
return v;
|
||||
}
|
||||
|
||||
/// Drains all elements to a Vec
|
||||
/// ```
|
||||
/// # use tinyvec::*;
|
||||
/// let mut av = array_vec!([i32; 7] => 1, 2, 3);
|
||||
/// let v = av.drain_to_vec();
|
||||
/// assert_eq!(v, &[1, 2, 3]);
|
||||
/// assert_eq!(v.capacity(), 3);
|
||||
/// ```
|
||||
pub fn drain_to_vec(&mut self) -> Vec<A::Item> {
|
||||
self.drain_to_vec_and_reserve(0)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+182
-56
@@ -137,40 +137,139 @@ impl<A: Array, I: SliceIndex<[A::Item]>> IndexMut<I> for TinyVec<A> {
|
||||
}
|
||||
|
||||
impl<A: Array> TinyVec<A> {
|
||||
/// Moves the content of the TinyVec to the heap, if it's inline.
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
pub fn move_to_the_heap(&mut self) {
|
||||
let len = match self {
|
||||
TinyVec::Heap(_) => return,
|
||||
TinyVec::Inline(ref arr) => arr.len(),
|
||||
/// Returns whether elements are on heap
|
||||
pub fn is_heap(&self) -> bool {
|
||||
match self {
|
||||
TinyVec::Heap(_) => true,
|
||||
TinyVec::Inline(_) => false,
|
||||
}
|
||||
}
|
||||
/// Returns whether elements are on stack
|
||||
pub fn is_inline(&self) -> bool {
|
||||
!self.is_heap()
|
||||
}
|
||||
|
||||
/// Shrinks the capacity of the vector as much as possible.\
|
||||
/// It is inlined if length is less than `A::CAPACITY`.
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 2] => 1, 2, 3);
|
||||
/// assert!(tv.is_heap());
|
||||
/// let _ = tv.pop();
|
||||
/// assert!(tv.is_heap());
|
||||
/// tv.shrink_to_fit();
|
||||
/// assert!(tv.is_inline());
|
||||
/// ```
|
||||
pub fn shrink_to_fit(&mut self)
|
||||
where A: Default,
|
||||
{
|
||||
let vec = match self {
|
||||
TinyVec::Inline(_) => return,
|
||||
TinyVec::Heap(h) => h,
|
||||
};
|
||||
|
||||
self.move_to_the_heap_and_reserve(len);
|
||||
if vec.len() > A::CAPACITY {
|
||||
return vec.shrink_to_fit();
|
||||
}
|
||||
|
||||
let movedvec = core::mem::replace(vec, Vec::new());
|
||||
|
||||
let mut av = ArrayVec::default();
|
||||
let mut rest = av.fill(movedvec);
|
||||
debug_assert!(rest.next().is_none());
|
||||
*self = TinyVec::Inline(av);
|
||||
}
|
||||
|
||||
/// Moves the content of the TinyVec to the heap, if it's inline.
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3);
|
||||
/// assert!(tv.is_inline());
|
||||
/// tv.move_to_the_heap();
|
||||
/// assert!(tv.is_heap());
|
||||
/// ```
|
||||
#[allow(clippy::missing_inline_in_public_items)]
|
||||
pub fn move_to_the_heap(&mut self) {
|
||||
let arr = match self {
|
||||
TinyVec::Heap(_) => return,
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
let v = arr.drain_to_vec();
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
|
||||
/// If TinyVec is inline, moves the content of it to the heap.
|
||||
/// Also reserves additional space.
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3);
|
||||
/// assert!(tv.is_inline());
|
||||
/// tv.move_to_the_heap_and_reserve(32);
|
||||
/// assert!(tv.is_heap());
|
||||
/// assert!(tv.capacity() >= 35);
|
||||
/// ```
|
||||
pub fn move_to_the_heap_and_reserve(&mut self, n: usize) {
|
||||
match self {
|
||||
TinyVec::Heap(h) => h.reserve(n),
|
||||
TinyVec::Inline(ref mut arr) => {
|
||||
let mut v = Vec::with_capacity(arr.len() + n);
|
||||
v.extend(arr.drain(..));
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
}
|
||||
let arr = match self {
|
||||
TinyVec::Heap(h) => return h.reserve(n),
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
let v = arr.drain_to_vec_and_reserve(n);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
|
||||
/// Reserves additional space.
|
||||
/// Moves to the heap if array can't hold `n` more items
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4);
|
||||
/// assert!(tv.is_inline());
|
||||
/// tv.reserve(1);
|
||||
/// assert!(tv.is_heap());
|
||||
/// assert!(tv.capacity() >= 5);
|
||||
/// ```
|
||||
pub fn reserve(&mut self, n: usize) {
|
||||
let arr = match self {
|
||||
TinyVec::Heap(h) => return h.reserve(n),
|
||||
TinyVec::Inline(ref mut a) => a,
|
||||
TinyVec::Heap(h) => return h.reserve(n),
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
if n > arr.capacity() - arr.len() {
|
||||
return self.move_to_the_heap_and_reserve(n);
|
||||
let v = arr.drain_to_vec_and_reserve(n);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
|
||||
/* In this place array has enough place, so no work is needed more */
|
||||
return;
|
||||
}
|
||||
|
||||
/// Reserves additional space.
|
||||
/// Moves to the heap if array can't hold `n` more items
|
||||
///
|
||||
/// 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.
|
||||
/// Prefer reserve if future insertions are expected.
|
||||
/// ```
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 4] => 1, 2, 3, 4);
|
||||
/// assert!(tv.is_inline());
|
||||
/// tv.reserve_exact(1);
|
||||
/// assert!(tv.is_heap());
|
||||
/// assert!(tv.capacity() >= 5);
|
||||
/// ```
|
||||
pub fn reserve_exact(&mut self, n: usize) {
|
||||
let arr = match self {
|
||||
TinyVec::Heap(h) => return h.reserve_exact(n),
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
if n > arr.capacity() - arr.len() {
|
||||
let v = arr.drain_to_vec_and_reserve(n);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
|
||||
/* In this place array has enough place, so no work is needed more */
|
||||
@@ -185,13 +284,9 @@ impl<A: Array> TinyVec<A> {
|
||||
self.reserve(other.len());
|
||||
let iter = other.drain(..);
|
||||
|
||||
let arr = match self {
|
||||
TinyVec::Heap(h) => return h.extend(iter),
|
||||
TinyVec::Inline(ref mut a) => a,
|
||||
};
|
||||
|
||||
for item in iter {
|
||||
arr.push(item)
|
||||
match self {
|
||||
TinyVec::Heap(h) => h.extend(iter),
|
||||
TinyVec::Inline(a) => a.extend(iter),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,6 +441,12 @@ impl<A: Array> TinyVec<A> {
|
||||
}
|
||||
|
||||
/// Clone each element of the slice into this vec.
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 4] => 1, 2);
|
||||
/// tv.extend_from_slice(&[3, 4]);
|
||||
/// assert_eq!(tv.as_slice(), [1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn extend_from_slice(&mut self, sli: &[A::Item])
|
||||
where
|
||||
@@ -353,8 +454,8 @@ impl<A: Array> TinyVec<A> {
|
||||
{
|
||||
self.reserve(sli.len());
|
||||
match self {
|
||||
TinyVec::Inline(ref mut a) => a.extend_from_slice(sli),
|
||||
TinyVec::Heap(ref mut h) => h.extend_from_slice(sli),
|
||||
TinyVec::Inline(a) => a.extend_from_slice(sli),
|
||||
TinyVec::Heap(h) => h.extend_from_slice(sli),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,16 +505,23 @@ impl<A: Array> TinyVec<A> {
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn insert(&mut self, index: usize, item: A::Item) {
|
||||
match self {
|
||||
TinyVec::Inline(a) => {
|
||||
if a.len() == A::CAPACITY {
|
||||
self.move_to_the_heap();
|
||||
self.insert(index, item)
|
||||
} else {
|
||||
a.insert(index, item);
|
||||
}
|
||||
}
|
||||
TinyVec::Heap(v) => v.insert(index, item),
|
||||
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::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()));
|
||||
v.extend(it.by_ref().take(index));
|
||||
v.push(x);
|
||||
v.extend(it);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -459,18 +567,24 @@ impl<A: Array> TinyVec<A> {
|
||||
/// Place an element onto the end of the vec.
|
||||
/// ## Panics
|
||||
/// * If the length of the vec would overflow the capacity.
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
/// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3);
|
||||
/// tv.push(4);
|
||||
/// assert_eq!(tv.as_slice(), &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push(&mut self, val: A::Item) {
|
||||
match self {
|
||||
TinyVec::Inline(a) => {
|
||||
if a.len() == A::CAPACITY {
|
||||
self.move_to_the_heap();
|
||||
self.push(val)
|
||||
} else {
|
||||
a.push(val);
|
||||
}
|
||||
}
|
||||
TinyVec::Heap(v) => v.push(val),
|
||||
let arr = match self {
|
||||
TinyVec::Heap(v) => return v.push(val),
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
if let Some(x) = arr.try_push(val) {
|
||||
/* Make the Vec twice the size to amortize the cost of draining */
|
||||
let mut v = arr.drain_to_vec_and_reserve(arr.len());
|
||||
v.push(x);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -534,11 +648,11 @@ impl<A: Array> TinyVec<A> {
|
||||
/// ```rust
|
||||
/// use tinyvec::*;
|
||||
///
|
||||
/// let mut tv = tiny_vec!([i32; 10] => 1, 2, 3);
|
||||
/// let mut tv = tiny_vec!([i32; 3] => 1, 2, 3);
|
||||
/// tv.resize_with(5, Default::default);
|
||||
/// assert_eq!(tv.as_slice(), &[1, 2, 3, 0, 0][..]);
|
||||
///
|
||||
/// let mut tv = tiny_vec!([i32; 10]);
|
||||
/// let mut tv = tiny_vec!([i32; 2]);
|
||||
/// let mut p = 1;
|
||||
/// tv.resize_with(4, || {
|
||||
/// p *= 2;
|
||||
@@ -555,7 +669,7 @@ impl<A: Array> TinyVec<A> {
|
||||
|
||||
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),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -725,9 +839,23 @@ impl<A: Array> Extend<A::Item> for TinyVec<A> {
|
||||
let (lower_bound, _) = iter.size_hint();
|
||||
self.reserve(lower_bound);
|
||||
|
||||
for t in iter {
|
||||
self.push(t)
|
||||
}
|
||||
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);
|
||||
*self = TinyVec::Heap(v);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -781,9 +909,7 @@ impl<A: Array + Default> FromIterator<A::Item> for TinyVec<A> {
|
||||
#[must_use]
|
||||
fn from_iter<T: IntoIterator<Item = A::Item>>(iter: T) -> Self {
|
||||
let mut av = Self::default();
|
||||
for i in iter {
|
||||
av.push(i)
|
||||
}
|
||||
av.extend(iter);
|
||||
av
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user