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:
bors-servo
2016-12-05 22:59:55 -08:00
committed by GitHub
2 changed files with 163 additions and 20 deletions
+1 -2
View File
@@ -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
+162 -18
View File
@@ -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");
}
}