mirror of
https://github.com/openharmony/third_party_rust_rust-smallvec.git
synced 2026-07-21 01:55:25 -04:00
Auto merge of #40 - mbrubeck:docs, r=Ms2ger
Docs, code cleanup, and misc. fixes for smallvec <!-- Reviewable:start --> This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/40) <!-- Reviewable:end -->
This commit is contained in:
+1
-2
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "smallvec"
|
||||
version = "0.3.0"
|
||||
version = "0.3.1"
|
||||
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
|
||||
license = "MPL-2.0"
|
||||
repository = "https://github.com/servo/rust-smallvec"
|
||||
@@ -12,4 +12,3 @@ documentation = "http://doc.servo.org/smallvec/"
|
||||
[lib]
|
||||
name = "smallvec"
|
||||
path = "lib.rs"
|
||||
doctest = false
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
//! Small vectors in various sizes. These store a certain number of elements inline and fall back
|
||||
//! to the heap for larger allocations.
|
||||
//! Small vectors in various sizes. These store a certain number of elements inline, and fall back
|
||||
//! to the heap for larger allocations. This can be a useful optimization for improving cache
|
||||
//! locality and reducing allocator traffic for workloads that fit within the inline buffer.
|
||||
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::cmp;
|
||||
@@ -17,7 +18,27 @@ use std::slice;
|
||||
|
||||
use SmallVecData::{Inline, Heap};
|
||||
|
||||
|
||||
/// Common operations implemented by both `Vec` and `SmallVec`.
|
||||
///
|
||||
/// This can be used to write generic code that works with both `Vec` and `SmallVec`.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use smallvec::{VecLike, SmallVec8};
|
||||
///
|
||||
/// fn initialize<V: VecLike<u8>>(v: &mut V) {
|
||||
/// for i in 0..5 {
|
||||
/// v.push(i);
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// let mut vec = Vec::new();
|
||||
/// initialize(&mut vec);
|
||||
///
|
||||
/// let mut small_vec = SmallVec8::new();
|
||||
/// initialize(&mut small_vec);
|
||||
/// ```
|
||||
pub trait VecLike<T>:
|
||||
ops::Index<usize, Output=T> +
|
||||
ops::IndexMut<usize> +
|
||||
@@ -32,11 +53,11 @@ pub trait VecLike<T>:
|
||||
ops::DerefMut<Target = [T]> +
|
||||
Extend<T> {
|
||||
|
||||
/// Append an element to the vector.
|
||||
fn push(&mut self, value: T);
|
||||
}
|
||||
|
||||
impl<T> VecLike<T> for Vec<T> {
|
||||
|
||||
#[inline]
|
||||
fn push(&mut self, value: T) {
|
||||
Vec::push(self, value);
|
||||
@@ -130,13 +151,45 @@ impl<A: Array> Drop for SmallVecData<A> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// A `Vec`-like container that can store a small number of elements inline.
|
||||
///
|
||||
/// `SmallVec` acts like a vector, but can store a limited amount of data inline within the
|
||||
/// `Smallvec` struct rather than in a separate allocation. If the data exceeds this limit, the
|
||||
/// `SmallVec` will "spill" its data onto the heap, allocating a new buffer to hold it.
|
||||
///
|
||||
/// The amount of data that a `SmallVec` can store inline depends on its backing store. The backing
|
||||
/// store can be any type that implements the `Array` trait; usually it is a small fixed-sized
|
||||
/// array. For example a `SmallVec<[u64; 8]>` can hold up to eight 64-bit integers inline.
|
||||
///
|
||||
/// Type aliases like `SmallVec8<T>` are provided as convenient shorthand for types like
|
||||
/// `SmallVec<[T; 8]>`.
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use smallvec::SmallVec;
|
||||
/// let mut v = SmallVec::<[u8; 4]>::new(); // initialize an empty vector
|
||||
///
|
||||
/// use smallvec::SmallVec4;
|
||||
/// let mut v: SmallVec4<u8> = SmallVec::new(); // alternate way to write the above
|
||||
///
|
||||
/// // SmallVec4 can hold up to 4 items without spilling onto the heap.
|
||||
/// v.extend(0..4);
|
||||
/// assert_eq!(v.len(), 4);
|
||||
/// assert!(!v.spilled());
|
||||
///
|
||||
/// // Pushing another element will force the buffer to spill:
|
||||
/// v.push(4);
|
||||
/// assert_eq!(v.len(), 5);
|
||||
/// assert!(v.spilled());
|
||||
/// ```
|
||||
pub struct SmallVec<A: Array> {
|
||||
len: usize,
|
||||
data: SmallVecData<A>,
|
||||
}
|
||||
|
||||
impl<A: Array> SmallVec<A> {
|
||||
/// Construct an empty vector
|
||||
#[inline]
|
||||
pub fn new() -> SmallVec<A> {
|
||||
unsafe {
|
||||
@@ -147,22 +200,35 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets the length of a vector.
|
||||
///
|
||||
/// This will explicitly set the size of the vector, without actually
|
||||
/// modifying its buffers, so it is up to the caller to ensure that the
|
||||
/// vector is actually the specified size.
|
||||
pub unsafe fn set_len(&mut self, new_len: usize) {
|
||||
self.len = new_len
|
||||
}
|
||||
|
||||
/// The maximum number of elements this vector can hold inline
|
||||
#[inline]
|
||||
pub fn inline_size(&self) -> usize {
|
||||
A::size()
|
||||
}
|
||||
|
||||
|
||||
/// The number of elements stored in the vector
|
||||
#[inline]
|
||||
pub fn len(&self) -> usize {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Returns `true` if the vector is empty
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
/// The number of items the vector can hold without reallocating
|
||||
#[inline]
|
||||
pub fn capacity(&self) -> usize {
|
||||
match self.data {
|
||||
Inline { .. } => A::size(),
|
||||
@@ -170,6 +236,8 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the data has spilled into a separate heap-allocated buffer.
|
||||
#[inline]
|
||||
pub fn spilled(&self) -> bool {
|
||||
match self.data {
|
||||
Inline { .. } => false,
|
||||
@@ -177,6 +245,7 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Empty the vector and return an iterator over its former contents.
|
||||
pub fn drain(&mut self) -> Drain<A::Item> {
|
||||
unsafe {
|
||||
let current_len = self.len();
|
||||
@@ -192,6 +261,8 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Append an item to the vector.
|
||||
#[inline]
|
||||
pub fn push(&mut self, value: A::Item) {
|
||||
let cap = self.capacity();
|
||||
if self.len == cap {
|
||||
@@ -205,12 +276,16 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Append elements from an iterator.
|
||||
///
|
||||
/// This function is deprecated; it has been replaced by `Extend::extend`.
|
||||
#[deprecated(note = "Use `extend` instead")]
|
||||
pub fn push_all_move<V: IntoIterator<Item=A::Item>>(&mut self, other: V) {
|
||||
for value in other {
|
||||
self.push(value)
|
||||
}
|
||||
self.extend(other)
|
||||
}
|
||||
|
||||
/// Remove an item from the end of the vector and return it, or None if empty.
|
||||
#[inline]
|
||||
pub fn pop(&mut self) -> Option<A::Item> {
|
||||
if self.len == 0 {
|
||||
return None
|
||||
@@ -227,7 +302,11 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Re-allocate to set the capacity to `new_cap`.
|
||||
///
|
||||
/// Panics if `new_cap` is less than the vector's length.
|
||||
pub fn grow(&mut self, new_cap: usize) {
|
||||
assert!(new_cap >= self.len);
|
||||
let mut vec: Vec<A::Item> = Vec::with_capacity(new_cap);
|
||||
let new_alloc = vec.as_mut_ptr();
|
||||
unsafe {
|
||||
@@ -245,6 +324,13 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reserve capacity for `additional` more elements to be inserted.
|
||||
///
|
||||
/// May reserve more space to avoid frequent reallocations.
|
||||
///
|
||||
/// If the new capacity would overflow `usize` then it will be set to `usize::max_value()`
|
||||
/// instead. (This means that inserting `additional` new elements is not guaranteed to be
|
||||
/// possible after calling this function.)
|
||||
pub fn reserve(&mut self, additional: usize) {
|
||||
let len = self.len();
|
||||
if self.capacity() - len < additional {
|
||||
@@ -255,6 +341,9 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Reserve the minumum capacity for `additional` more elements to be inserted.
|
||||
///
|
||||
/// Panics if the new capacity overflows `usize`.
|
||||
pub fn reserve_exact(&mut self, additional: usize) {
|
||||
let len = self.len();
|
||||
if self.capacity() - len < additional {
|
||||
@@ -265,13 +354,34 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shrink the capacity of the vector as much as possible.
|
||||
///
|
||||
/// When possible, this will move data from an external heap buffer to the vector's inline
|
||||
/// storage.
|
||||
pub fn shrink_to_fit(&mut self) {
|
||||
let len = self.len;
|
||||
if self.spilled() && self.capacity() > len {
|
||||
if self.inline_size() >= len {
|
||||
unsafe {
|
||||
let (ptr, capacity) = match self.data {
|
||||
Inline { .. } => return,
|
||||
Heap { ptr, capacity } => (ptr, capacity),
|
||||
};
|
||||
ptr::write(&mut self.data, Inline { array: mem::uninitialized() });
|
||||
ptr::copy_nonoverlapping(ptr, self.as_mut_ptr(), len);
|
||||
deallocate(ptr, capacity);
|
||||
}
|
||||
} else if self.capacity() > len {
|
||||
self.grow(len);
|
||||
}
|
||||
}
|
||||
|
||||
/// Shorten the vector, keeping the first `len` elements and dropping the rest.
|
||||
///
|
||||
/// If `len` is greater than or equal to the vector's current length, this has no
|
||||
/// effect.
|
||||
///
|
||||
/// This does not re-allocate. If you want the vector's capacity to shrink, call
|
||||
/// `shrink_to_fit` after truncating.
|
||||
pub fn truncate(&mut self, len: usize) {
|
||||
let end_ptr = self.as_ptr();
|
||||
while len < self.len {
|
||||
@@ -283,16 +393,28 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove the element at position `index`, replacing it with the last element.
|
||||
///
|
||||
/// This does not preserve ordering, but is O(1).
|
||||
///
|
||||
/// Panics if `index` is out of bounds.
|
||||
#[inline]
|
||||
pub fn swap_remove(&mut self, index: usize) -> A::Item {
|
||||
let len = self.len;
|
||||
self.swap(len - 1, index);
|
||||
self.pop().unwrap()
|
||||
}
|
||||
|
||||
/// Remove all elements from the vector.
|
||||
#[inline]
|
||||
pub fn clear(&mut self) {
|
||||
self.truncate(0);
|
||||
}
|
||||
|
||||
/// Remove and return the element at position `index`, shifting all elements after it to the
|
||||
/// left.
|
||||
///
|
||||
/// Panics if `index` is out of bounds.
|
||||
pub fn remove(&mut self, index: usize) -> A::Item {
|
||||
let len = self.len();
|
||||
|
||||
@@ -307,6 +429,9 @@ impl<A: Array> SmallVec<A> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert an element at position `index`, shifting all elements after it to the right.
|
||||
///
|
||||
/// Panics if `index` is out of bounds.
|
||||
pub fn insert(&mut self, index: usize, element: A::Item) {
|
||||
self.reserve(1);
|
||||
|
||||
@@ -521,11 +646,11 @@ impl<A: Array> Drop for IntoIter<A> {
|
||||
|
||||
impl<A: Array> Iterator for IntoIter<A> {
|
||||
type Item = A::Item;
|
||||
|
||||
|
||||
#[inline]
|
||||
fn next(&mut self) -> Option<A::Item> {
|
||||
if self.current == self.end {
|
||||
None
|
||||
None
|
||||
}
|
||||
else {
|
||||
unsafe {
|
||||
@@ -547,7 +672,7 @@ impl<A: Array> DoubleEndedIterator for IntoIter<A> {
|
||||
#[inline]
|
||||
fn next_back(&mut self) -> Option<A::Item> {
|
||||
if self.current == self.end {
|
||||
None
|
||||
None
|
||||
}
|
||||
else {
|
||||
unsafe {
|
||||
@@ -624,7 +749,7 @@ pub type SmallVec24<T> = SmallVec<[T; 24]>;
|
||||
#[deprecated]
|
||||
pub type SmallVec32<T> = SmallVec<[T; 32]>;
|
||||
|
||||
|
||||
/// Types that can be used as the backing store for a SmallVec
|
||||
pub unsafe trait Array {
|
||||
type Item;
|
||||
fn size() -> usize;
|
||||
@@ -653,6 +778,7 @@ impl_array!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32,
|
||||
pub mod tests {
|
||||
use SmallVec;
|
||||
use std::borrow::ToOwned;
|
||||
use std::iter::FromIterator;
|
||||
|
||||
// We heap allocate all these strings so that double frees will show up under valgrind.
|
||||
|
||||
@@ -784,7 +910,7 @@ pub mod tests {
|
||||
self.0.set(self.0.get() + 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
let cell = Cell::new(0);
|
||||
let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new();
|
||||
@@ -864,6 +990,14 @@ pub mod tests {
|
||||
assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[0, 3, 2]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_invalid_grow() {
|
||||
let mut v: SmallVec<[u8; 8]> = SmallVec::new();
|
||||
v.extend(0..8);
|
||||
v.grow(5);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn test_drop_panic_smallvec() {
|
||||
@@ -922,20 +1056,21 @@ pub mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_hash() {
|
||||
use std::hash::{Hash, SipHasher};
|
||||
use std::hash::Hash;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
|
||||
{
|
||||
let mut a: SmallVec<[u32; 2]> = SmallVec::new();
|
||||
let b = [1, 2];
|
||||
a.extend(b.iter().cloned());
|
||||
let mut hasher = SipHasher::new();
|
||||
let mut hasher = DefaultHasher::new();
|
||||
assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher));
|
||||
}
|
||||
{
|
||||
let mut a: SmallVec<[u32; 2]> = SmallVec::new();
|
||||
let b = [1, 2, 11, 12];
|
||||
a.extend(b.iter().cloned());
|
||||
let mut hasher = SipHasher::new();
|
||||
let mut hasher = DefaultHasher::new();
|
||||
assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher));
|
||||
}
|
||||
}
|
||||
@@ -1020,4 +1155,13 @@ pub mod tests {
|
||||
let mut vec = SmallVec::<[i32; 2]>::from(&[3, 1, 2][..]);
|
||||
test(&mut vec);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn shrink_to_fit_unspill() {
|
||||
let mut vec = SmallVec::<[u8; 2]>::from_iter(0..3);
|
||||
vec.pop();
|
||||
assert!(vec.spilled());
|
||||
vec.shrink_to_fit();
|
||||
assert!(!vec.spilled(), "shrink_to_fit will un-spill if possible");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user