From 9534a6b2aab073fbd085ae5795bf08f3795b2fa9 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 16:28:20 -0300 Subject: [PATCH 01/24] Modifies lib.rs and Cargo.toml lib.rs: Alloc feature Cargo.toml: New features and 2018 edition --- Cargo.toml | 37 +++++++++++++++-------------- lib.rs | 68 ++++++++++++++++++++++++------------------------------ 2 files changed, 50 insertions(+), 55 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fcea83c..3e52e5a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,28 +1,31 @@ [package] -name = "smallvec" -version = "0.6.10" authors = ["Simon Sapin "] -license = "MIT/Apache-2.0" -repository = "https://github.com/servo/rust-smallvec" -description = "'Small vector' optimization: store up to a small number of items on the stack" -keywords = ["small", "vec", "vector", "stack", "no_std"] categories = ["data-structures"] -readme = "README.md" +description = "'Small vector' optimization: store up to a small number of items on the stack" documentation = "https://doc.servo.org/smallvec/" - -[features] -std = [] -union = [] -default = ["std"] -specialization = [] -may_dangle = [] - -[lib] +edition = "2018" +keywords = ["small", "vec", "vector", "stack", "no_std"] +license = "MIT/Apache-2.0" name = "smallvec" -path = "lib.rs" +readme = "README.md" +repository = "https://github.com/servo/rust-smallvec" +version = "0.6.10" [dependencies] serde = { version = "1", optional = true } [dev_dependencies] bincode = "1.0.1" + +[features] +alloc = [] +const_generics = [] +default = ["alloc"] +may_dangle = [] +specialization = [] +std = ["alloc"] +union = [] + +[lib] +name = "smallvec" +path = "lib.rs" \ No newline at end of file diff --git a/lib.rs b/lib.rs index e45ca7a..348ff37 100644 --- a/lib.rs +++ b/lib.rs @@ -28,47 +28,39 @@ //! To use this feature add `features = ["union"]` in the `smallvec` section of Cargo.toml. //! Note that this feature requires a nightly compiler (for now). -#![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(not(feature = "std"), feature(alloc))] -#![cfg_attr(feature = "union", feature(untagged_unions))] -#![cfg_attr(feature = "specialization", feature(specialization))] #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] +#![cfg_attr(feature = "specialization", feature(specialization))] +#![cfg_attr(feature = "union", feature(untagged_unions))] +#![cfg_attr(not(feature = "alloc"), no_std)] #![deny(missing_docs)] - -#[cfg(not(feature = "std"))] -#[macro_use] +#[cfg(feature = "alloc")] extern crate alloc; -#[cfg(not(feature = "std"))] -use alloc::vec::Vec; - #[cfg(feature = "serde")] extern crate serde; -#[cfg(not(feature = "std"))] -mod std { - pub use core::*; -} - -use std::borrow::{Borrow, BorrowMut}; -use std::cmp; -use std::fmt; -use std::hash::{Hash, Hasher}; -use std::iter::{IntoIterator, FromIterator, repeat}; -use std::mem; -use std::mem::ManuallyDrop; -use std::ops; -use std::ptr; -use std::slice; +use core::{ + borrow::{Borrow, BorrowMut}, + cmp, + fmt, + hash::{Hash, Hasher}, + iter::{IntoIterator, FromIterator, repeat}, + mem::{ManuallyDrop, self}, + ops, + ptr, + slice, +}; #[cfg(feature = "std")] use std::io; #[cfg(feature = "serde")] -use serde::ser::{Serialize, Serializer, SerializeSeq}; -#[cfg(feature = "serde")] -use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor}; -#[cfg(feature = "serde")] -use std::marker::PhantomData; +use { + serde::{ + ser::{Serialize, Serializer, SerializeSeq}, + de::{Deserialize, Deserializer, SeqAccess, Visitor}, + }, + core::marker::PhantomData +}; /// Creates a [`SmallVec`] containing the arguments. /// @@ -821,7 +813,7 @@ impl SmallVec { } let (lower_size_bound, _) = iter.size_hint(); - assert!(lower_size_bound <= std::isize::MAX as usize); // Ensure offset is indexable + assert!(lower_size_bound <= core::isize::MAX as usize); // Ensure offset is indexable assert!(index + lower_size_bound >= index); // Protect against overflow self.reserve(lower_size_bound); @@ -1121,7 +1113,7 @@ impl SmallVec where A::Item: Clone { let mut local_len = SetLenOnDrop::new(len_ptr); for i in 0..n as isize { - ::std::ptr::write(ptr.offset(i), elem.clone()); + core::ptr::write(ptr.offset(i), elem.clone()); local_len.increment_len(1); } } @@ -1606,9 +1598,9 @@ impl_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32 #[cfg(test)] mod tests { - use SmallVec; + use crate::SmallVec; - use std::iter::FromIterator; + use core::iter::FromIterator; #[cfg(feature = "std")] use std::borrow::ToOwned; @@ -1766,7 +1758,7 @@ mod tests { #[test] fn into_iter_drop() { - use std::cell::Cell; + use core::cell::Cell; struct DropCounter<'a>(&'a Cell); @@ -2061,7 +2053,7 @@ mod tests { #[test] fn test_borrow() { - use std::borrow::Borrow; + use core::borrow::Borrow; let mut a: SmallVec<[u32; 2]> = SmallVec::new(); a.push(1); @@ -2074,7 +2066,7 @@ mod tests { #[test] fn test_borrow_mut() { - use std::borrow::BorrowMut; + use core::borrow::BorrowMut; let mut a: SmallVec<[u32; 2]> = SmallVec::new(); a.push(1); @@ -2279,7 +2271,7 @@ mod tests { #[cfg(feature = "std")] #[test] fn test_write() { - use io::Write; + use std::io::Write; let data = [1, 2, 3, 4, 5]; From 0b90d2101ec0e52b06332832937ab8849c09a91a Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 16:29:08 -0300 Subject: [PATCH 02/24] Removes the VecLike struct --- lib.rs | 72 ---------------------------------------------------------- 1 file changed, 72 deletions(-) diff --git a/lib.rs b/lib.rs index 348ff37..592eaea 100644 --- a/lib.rs +++ b/lib.rs @@ -144,54 +144,6 @@ macro_rules! debug_unreachable { } } -/// 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, SmallVec}; -/// -/// fn initialize>(v: &mut V) { -/// for i in 0..5 { -/// v.push(i); -/// } -/// } -/// -/// let mut vec = Vec::new(); -/// initialize(&mut vec); -/// -/// let mut small_vec = SmallVec::<[u8; 8]>::new(); -/// initialize(&mut small_vec); -/// ``` -#[deprecated(note = "Use `Extend` and `Deref<[T]>` instead")] -pub trait VecLike: - ops::Index + - ops::IndexMut + - ops::Index, Output=[T]> + - ops::IndexMut> + - ops::Index, Output=[T]> + - ops::IndexMut> + - ops::Index, Output=[T]> + - ops::IndexMut> + - ops::Index + - ops::IndexMut + - ops::DerefMut + - Extend { - - /// Append an element to the vector. - fn push(&mut self, value: T); -} - -#[allow(deprecated)] -impl VecLike for Vec { - #[inline] - fn push(&mut self, value: T) { - Vec::push(self, value); - } -} - /// Trait to be implemented by a collection that can be extended from a slice /// /// ## Example @@ -1320,13 +1272,6 @@ impl ExtendFromSlice for SmallVec where A::Item: Copy { } } -#[allow(deprecated)] -impl VecLike for SmallVec { - #[inline] - fn push(&mut self, value: A::Item) { - SmallVec::push(self, value); - } -} impl FromIterator for SmallVec { fn from_iter>(iterable: I) -> SmallVec { @@ -2123,23 +2068,6 @@ mod tests { assert_eq!(vec.drain().len(), 3); } - #[test] - #[allow(deprecated)] - fn veclike_deref_slice() { - use super::VecLike; - - fn test>(vec: &mut T) { - assert!(!vec.is_empty()); - assert_eq!(vec.len(), 3); - - vec.sort(); - assert_eq!(&vec[..], [1, 2, 3]); - } - - 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); From 8de1d3baa761268225ffe13275f63eeae5064176 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 16:29:55 -0300 Subject: [PATCH 03/24] New scripts for testing For testing in development and CI --- scripts/test-all.sh | 6 ++++++ scripts/test-common.sh | 11 +++++++++++ scripts/test-nightly.sh | 36 ++++++++++++++++++++++++++++++++++++ scripts/test-stable.sh | 19 +++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100755 scripts/test-all.sh create mode 100644 scripts/test-common.sh create mode 100755 scripts/test-nightly.sh create mode 100755 scripts/test-stable.sh diff --git a/scripts/test-all.sh b/scripts/test-all.sh new file mode 100755 index 0000000..36c43eb --- /dev/null +++ b/scripts/test-all.sh @@ -0,0 +1,6 @@ +#!/usr/bin/env bash + +set -e + +./test-stable.sh +./test-nightly.sh \ No newline at end of file diff --git a/scripts/test-common.sh b/scripts/test-common.sh new file mode 100644 index 0000000..e02bc83 --- /dev/null +++ b/scripts/test-common.sh @@ -0,0 +1,11 @@ +STABLE_FEATURES=( + alloc + serde + std +) + +test_with_feature() { + local feature=$1 + /bin/echo -e "\e[0;33m***** Testing with feature '${feature}' *****\e[0m\n" + cargo test --features "${feature}" --no-default-features --verbose +} \ No newline at end of file diff --git a/scripts/test-nightly.sh b/scripts/test-nightly.sh new file mode 100755 index 0000000..0c03707 --- /dev/null +++ b/scripts/test-nightly.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash + +set -e +. ./test-common.sh --source-only + +# All nightly features individually + +NIGHTLY_FEATURES=( + may_dangle + specialization + union +) + +for feature in "${NIGHTLY_FEATURES[@]}"; do + test_with_feature $feature +done + +# All nightly features individually with constant generics + +# for feature in "${STABLE_FEATURES[@]}"; do +# test_with_feature "const_generic, $feature" +# done + +# for feature in "${NIGHTLY_FEATURES[@]}"; do +# test_with_feature "const_generic, $feature" +# done + +# All features + +# /bin/echo -e "\e[0;33m***** Testing all features *****\e[0m\n" +# cargo test --all-features --no-default-features --verbose + +# Run bench + +/bin/echo -e "\e[0;33m***** Running bench *****\e[0m\n" +cargo bench --verbose bench diff --git a/scripts/test-stable.sh b/scripts/test-stable.sh new file mode 100755 index 0000000..c522daf --- /dev/null +++ b/scripts/test-stable.sh @@ -0,0 +1,19 @@ +#!/usr/bin/env bash + +set -e +. ./test-common.sh --source-only + +# No features + +/bin/echo -e "\e[0;33m***** Testing without features *****\e[0m\n" +cargo test --no-default-features --verbose + +# All stable features individually + +for feature in "${STABLE_FEATURES[@]}"; do + test_with_feature $feature +done + +# All stable features at once + +test_with_feature $(IFS=, ; echo "${STABLE_FEATURES[*]}") From 93f9909c058dec1d2bff89dc55a9eb34b1850a0b Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 16:30:11 -0300 Subject: [PATCH 04/24] Updates the Travis.yml file --- .travis.yml | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee744e1..77d1f0c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,14 +1,11 @@ language: rust rust: - - 1.20.0 + #- 1.36.0 - nightly - beta - - stable -script: | - cargo build --verbose && - cargo test --verbose && - cargo test --verbose --features serde && - ([ $TRAVIS_RUST_VERSION != nightly ] || cargo check --verbose --no-default-features) && - ([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --verbose --features union) && - ([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --verbose --all-features) && - ([ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose bench) + #- stable +script: + - pushd ./scripts + - ./test-stable.sh + - ([ $TRAVIS_RUST_VERSION != nightly ] || ./test-nightly.sh) + - popd From 4e70e254862dbddcac6c44e14a08d1f3ea5d6e23 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 16:32:53 -0300 Subject: [PATCH 05/24] Modifies the Array trait Method names are now matching std --- lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib.rs b/lib.rs index 592eaea..9804fdf 100644 --- a/lib.rs +++ b/lib.rs @@ -395,7 +395,7 @@ impl SmallVec { let mut data = SmallVecData::::from_inline(mem::uninitialized()); let len = vec.len(); vec.set_len(0); - ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len); + ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().as_mut_ptr(), len); SmallVec { capacity: len, @@ -516,7 +516,7 @@ impl SmallVec { let (ptr, len) = self.data.heap(); (ptr, len, self.capacity) } else { - (self.data.inline().ptr(), self.capacity, A::size()) + (self.data.inline().as_ptr(), self.capacity, A::size()) } } } @@ -529,7 +529,7 @@ impl SmallVec { let &mut (ptr, ref mut len_ptr) = self.data.heap_mut(); (ptr, len_ptr, self.capacity) } else { - (self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size()) + (self.data.inline_mut().as_mut_ptr(), &mut self.capacity, A::size()) } } } @@ -597,7 +597,7 @@ impl SmallVec { return; } self.data = SmallVecData::from_inline(mem::uninitialized()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); self.capacity = len; } else if new_cap != cap { let mut vec = Vec::with_capacity(new_cap); @@ -663,7 +663,7 @@ impl SmallVec { unsafe { let (ptr, len) = self.data.heap(); self.data = SmallVecData::from_inline(mem::uninitialized()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); deallocate(ptr, self.capacity); self.capacity = len; } @@ -987,7 +987,7 @@ impl SmallVec where A::Item: Copy { capacity: len, data: SmallVecData::from_inline(unsafe { let mut data: A = mem::uninitialized(); - ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len); + ptr::copy_nonoverlapping(slice.as_ptr(), data.as_mut_ptr(), len); data }) } @@ -1484,12 +1484,12 @@ impl<'a, A: Array> IntoIterator for &'a mut SmallVec { pub unsafe trait Array { /// The type of the array's elements. type Item; + /// Returns a mutable pointer to the first element of the array. + fn as_mut_ptr(&mut self) -> *mut Self::Item; + /// Returns a pointer to the first element of the array. + fn as_ptr(&self) -> *const Self::Item; /// Returns the number of items the array can hold. fn size() -> usize; - /// Returns a pointer to the first element of the array. - fn ptr(&self) -> *const Self::Item; - /// Returns a mutable pointer to the first element of the array. - fn ptr_mut(&mut self) -> *mut Self::Item; } /// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. @@ -1529,9 +1529,9 @@ macro_rules! impl_array( $( unsafe impl Array for [T; $size] { type Item = T; + fn as_mut_ptr(&mut self) -> *mut T { self.as_mut().as_mut_ptr() } + fn as_ptr(&self) -> *const T { self.as_ref().as_ptr() } fn size() -> usize { $size } - fn ptr(&self) -> *const T { self.as_ptr() } - fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() } } )+ } From c109e5c02ac8f64843d368c083dcb8b43e3b8bca Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 20:50:01 -0300 Subject: [PATCH 06/24] Do not use the no_std feature --- Cargo.toml | 4 +- benches/bench.rs | 14 ++++--- lib.rs | 83 +++++++++++++++++------------------------- scripts/test-common.sh | 1 - 4 files changed, 43 insertions(+), 59 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3e52e5a..660806a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,12 +18,10 @@ serde = { version = "1", optional = true } bincode = "1.0.1" [features] -alloc = [] const_generics = [] -default = ["alloc"] may_dangle = [] specialization = [] -std = ["alloc"] +std = [] union = [] [lib] diff --git a/benches/bench.rs b/benches/bench.rs index 36cb133..058c530 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -1,11 +1,9 @@ #![feature(test)] -#[macro_use] -extern crate smallvec; extern crate test; -use self::test::Bencher; -use smallvec::{ExtendFromSlice, SmallVec}; +use test::Bencher; +use smallvec::{smallvec, ExtendFromSlice, SmallVec}; const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; @@ -273,7 +271,11 @@ fn bench_insert_from_slice(b: &mut Bencher) { #[bench] fn bench_macro_from_list(b: &mut Bencher) { b.iter(|| { - let vec: SmallVec<[u64; 16]> = smallvec![ + #[cfg(feature = "const_generics")] + let vec: SmallVec; + #[cfg(not(feature = "const_generics"))] + let vec: SmallVec<[u64; 16]>; + vec = smallvec![ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000, @@ -292,4 +294,4 @@ fn bench_macro_from_list_vec(b: &mut Bencher) { ]; vec }); -} +} \ No newline at end of file diff --git a/lib.rs b/lib.rs index 9804fdf..6dbece2 100644 --- a/lib.rs +++ b/lib.rs @@ -31,15 +31,8 @@ #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #![cfg_attr(feature = "specialization", feature(specialization))] #![cfg_attr(feature = "union", feature(untagged_unions))] -#![cfg_attr(not(feature = "alloc"), no_std)] #![deny(missing_docs)] -#[cfg(feature = "alloc")] -extern crate alloc; - -#[cfg(feature = "serde")] -extern crate serde; - use core::{ borrow::{Borrow, BorrowMut}, cmp, @@ -1543,23 +1536,15 @@ impl_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32 #[cfg(test)] mod tests { - use crate::SmallVec; + extern crate alloc; + use crate::SmallVec; + use alloc::{ + rc::Rc, + boxed::Box, + }; use core::iter::FromIterator; - #[cfg(feature = "std")] - use std::borrow::ToOwned; - #[cfg(not(feature = "std"))] - use alloc::borrow::ToOwned; - #[cfg(feature = "std")] - use std::rc::Rc; - #[cfg(not(feature = "std"))] - use alloc::rc::Rc; - #[cfg(not(feature = "std"))] - use alloc::boxed::Box; - #[cfg(not(feature = "std"))] - use alloc::vec::Vec; - #[test] pub fn test_zero() { let mut v = SmallVec::<[_; 0]>::new(); @@ -1574,51 +1559,51 @@ mod tests { #[test] pub fn test_inline() { let mut v = SmallVec::<[_; 16]>::new(); - v.push("hello".to_owned()); - v.push("there".to_owned()); + v.push("hello"); + v.push("there"); assert_eq!(&*v, &[ - "hello".to_owned(), - "there".to_owned(), + "hello", + "there", ][..]); } #[test] pub fn test_spill() { let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello".to_owned()); + v.push("hello"); assert_eq!(v[0], "hello"); - v.push("there".to_owned()); - v.push("burma".to_owned()); + v.push("there"); + v.push("burma"); assert_eq!(v[0], "hello"); - v.push("shave".to_owned()); + v.push("shave"); assert_eq!(&*v, &[ - "hello".to_owned(), - "there".to_owned(), - "burma".to_owned(), - "shave".to_owned(), + "hello", + "there", + "burma", + "shave", ][..]); } #[test] pub fn test_double_spill() { let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello".to_owned()); - v.push("there".to_owned()); - v.push("burma".to_owned()); - v.push("shave".to_owned()); - v.push("hello".to_owned()); - v.push("there".to_owned()); - v.push("burma".to_owned()); - v.push("shave".to_owned()); + v.push("hello"); + v.push("there"); + v.push("burma"); + v.push("shave"); + v.push("hello"); + v.push("there"); + v.push("burma"); + v.push("shave"); assert_eq!(&*v, &[ - "hello".to_owned(), - "there".to_owned(), - "burma".to_owned(), - "shave".to_owned(), - "hello".to_owned(), - "there".to_owned(), - "burma".to_owned(), - "shave".to_owned(), + "hello", + "there", + "burma", + "shave", + "hello", + "there", + "burma", + "shave", ][..]); } diff --git a/scripts/test-common.sh b/scripts/test-common.sh index e02bc83..75b56d2 100644 --- a/scripts/test-common.sh +++ b/scripts/test-common.sh @@ -1,5 +1,4 @@ STABLE_FEATURES=( - alloc serde std ) From 7f73f8ab7273be90a5e9421f013e6a7ad54b71b9 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 20:53:33 -0300 Subject: [PATCH 07/24] Make use of NonNull --- lib.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lib.rs b/lib.rs index 6dbece2..29e4e12 100644 --- a/lib.rs +++ b/lib.rs @@ -41,7 +41,7 @@ use core::{ iter::{IntoIterator, FromIterator, repeat}, mem::{ManuallyDrop, self}, ops, - ptr, + ptr::{self, NonNull}, slice, }; #[cfg(feature = "std")] @@ -214,7 +214,7 @@ impl<'a, T: 'a> Drop for Drain<'a,T> { #[cfg(feature = "union")] union SmallVecData { inline: ManuallyDrop, - heap: (*mut A::Item, usize), + heap: (NonNull, usize), } #[cfg(feature = "union")] @@ -235,22 +235,22 @@ impl SmallVecData { unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) } #[inline] unsafe fn heap(&self) -> (*mut A::Item, usize) { - self.heap + (self.heap.0.as_ptr(), self.heap.1) } #[inline] - unsafe fn heap_mut(&mut self) -> &mut (*mut A::Item, usize) { - &mut self.heap + unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { + (self.heap.0.as_ptr(), &mut self.heap.1) } #[inline] fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { - SmallVecData { heap: (ptr, len) } + SmallVecData { heap: (NonNull::new(ptr).unwrap(), len) } } } #[cfg(not(feature = "union"))] enum SmallVecData { Inline(ManuallyDrop), - Heap((*mut A::Item, usize)), + Heap((NonNull, usize)), } #[cfg(not(feature = "union"))] @@ -283,20 +283,20 @@ impl SmallVecData { #[inline] unsafe fn heap(&self) -> (*mut A::Item, usize) { match *self { - SmallVecData::Heap(data) => data, + SmallVecData::Heap(data) => (data.0.as_ptr(), data.1), _ => debug_unreachable!(), } } #[inline] - unsafe fn heap_mut(&mut self) -> &mut (*mut A::Item, usize) { + unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { match *self { - SmallVecData::Heap(ref mut data) => data, + SmallVecData::Heap(ref mut data) => (data.0.as_ptr(), &mut data.1), _ => debug_unreachable!(), } } #[inline] fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { - SmallVecData::Heap((ptr, len)) + SmallVecData::Heap((NonNull::new(ptr).unwrap(), len)) } } @@ -519,7 +519,7 @@ impl SmallVec { fn triple_mut(&mut self) -> (*mut A::Item, &mut usize, usize) { unsafe { if self.spilled() { - let &mut (ptr, ref mut len_ptr) = self.data.heap_mut(); + let (ptr, len_ptr) = self.data.heap_mut(); (ptr, len_ptr, self.capacity) } else { (self.data.inline_mut().as_mut_ptr(), &mut self.capacity, A::size()) From e1bb0972ac61c70062e78381f49cc5ea99efbb93 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 20:53:44 -0300 Subject: [PATCH 08/24] Make use of MaybeUninit --- lib.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib.rs b/lib.rs index 29e4e12..1672f29 100644 --- a/lib.rs +++ b/lib.rs @@ -39,7 +39,7 @@ use core::{ fmt, hash::{Hash, Hasher}, iter::{IntoIterator, FromIterator, repeat}, - mem::{ManuallyDrop, self}, + mem::{MaybeUninit, self}, ops, ptr::{self, NonNull}, slice, @@ -213,7 +213,7 @@ impl<'a, T: 'a> Drop for Drain<'a,T> { #[cfg(feature = "union")] union SmallVecData { - inline: ManuallyDrop, + inline: MaybeUninit, heap: (NonNull, usize), } @@ -221,18 +221,18 @@ union SmallVecData { impl SmallVecData { #[inline] unsafe fn inline(&self) -> &A { - &self.inline + &*self.inline.as_ptr() } #[inline] unsafe fn inline_mut(&mut self) -> &mut A { - &mut self.inline + &mut *self.inline.as_mut_ptr() } #[inline] - fn from_inline(inline: A) -> SmallVecData { - SmallVecData { inline: ManuallyDrop::new(inline) } + fn from_inline(inline: MaybeUninit) -> SmallVecData { + SmallVecData { inline } } #[inline] - unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) } + unsafe fn into_inline(self) -> A { self.inline.assume_init() } #[inline] unsafe fn heap(&self) -> (*mut A::Item, usize) { (self.heap.0.as_ptr(), self.heap.1) @@ -249,7 +249,7 @@ impl SmallVecData { #[cfg(not(feature = "union"))] enum SmallVecData { - Inline(ManuallyDrop), + Inline(MaybeUninit), Heap((NonNull, usize)), } @@ -258,25 +258,25 @@ impl SmallVecData { #[inline] unsafe fn inline(&self) -> &A { match *self { - SmallVecData::Inline(ref a) => a, + SmallVecData::Inline(ref a) => &*a.as_ptr(), _ => debug_unreachable!(), } } #[inline] unsafe fn inline_mut(&mut self) -> &mut A { match *self { - SmallVecData::Inline(ref mut a) => a, + SmallVecData::Inline(ref mut a) => &mut *a.as_mut_ptr(), _ => debug_unreachable!(), } } #[inline] - fn from_inline(inline: A) -> SmallVecData { - SmallVecData::Inline(ManuallyDrop::new(inline)) + fn from_inline(inline: MaybeUninit) -> SmallVecData { + SmallVecData::Inline(inline) } #[inline] unsafe fn into_inline(self) -> A { match self { - SmallVecData::Inline(a) => ManuallyDrop::into_inner(a), + SmallVecData::Inline(a) => a.assume_init(), _ => debug_unreachable!(), } } @@ -421,7 +421,7 @@ impl SmallVec { pub fn from_buf(buf: A) -> SmallVec { SmallVec { capacity: A::size(), - data: SmallVecData::from_inline(buf), + data: SmallVecData::from_inline(MaybeUninit::new(buf)), } } @@ -461,7 +461,7 @@ impl SmallVec { pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec { SmallVec { capacity: len, - data: SmallVecData::from_inline(buf), + data: SmallVecData::from_inline(MaybeUninit::new(buf)), } } @@ -979,8 +979,9 @@ impl SmallVec where A::Item: Copy { SmallVec { capacity: len, data: SmallVecData::from_inline(unsafe { - let mut data: A = mem::uninitialized(); - ptr::copy_nonoverlapping(slice.as_ptr(), data.as_mut_ptr(), len); + let mut data = MaybeUninit::::uninit(); + let slice_mut = &mut *data.as_mut_ptr(); + ptr::copy_nonoverlapping(slice.as_ptr(), slice_mut.as_mut_ptr(), len); data }) } @@ -994,7 +995,6 @@ impl SmallVec where A::Item: Copy { } } } - /// Copy elements from a slice into the vector at position `index`, shifting any following /// elements toward the back. /// From d3a6c9c64bcb5703aeed23941e95f5f116c2de9a Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 20:55:37 -0300 Subject: [PATCH 09/24] Rustfmt --- lib.rs | 322 +++++++++++++++++++++++++++++++++++++-------------------- 1 file changed, 209 insertions(+), 113 deletions(-) diff --git a/lib.rs b/lib.rs index 1672f29..52f40c4 100644 --- a/lib.rs +++ b/lib.rs @@ -35,11 +35,10 @@ use core::{ borrow::{Borrow, BorrowMut}, - cmp, - fmt, + cmp, fmt, hash::{Hash, Hasher}, - iter::{IntoIterator, FromIterator, repeat}, - mem::{MaybeUninit, self}, + iter::{repeat, FromIterator, IntoIterator}, + mem::{self, MaybeUninit}, ops, ptr::{self, NonNull}, slice, @@ -48,11 +47,11 @@ use core::{ use std::io; #[cfg(feature = "serde")] use { + core::marker::PhantomData, serde::{ - ser::{Serialize, Serializer, SerializeSeq}, de::{Deserialize, Deserializer, SeqAccess, Visitor}, + ser::{Serialize, SerializeSeq, Serializer}, }, - core::marker::PhantomData }; /// Creates a [`SmallVec`] containing the arguments. @@ -127,14 +126,16 @@ pub unsafe fn unreachable() -> ! { /// `panic!()` in debug builds, optimization hint in release. #[cfg(not(feature = "union"))] macro_rules! debug_unreachable { - () => { debug_unreachable!("entered unreachable code") }; + () => { + debug_unreachable!("entered unreachable code") + }; ($e:expr) => { if cfg!(not(debug_assertions)) { unreachable(); } else { panic!($e); } - } + }; } /// Trait to be implemented by a collection that can be extended from a slice @@ -178,15 +179,17 @@ unsafe fn deallocate(ptr: *mut T, capacity: usize) { /// /// [1]: struct.SmallVec.html#method.drain pub struct Drain<'a, T: 'a> { - iter: slice::IterMut<'a,T>, + iter: slice::IterMut<'a, T>, } -impl<'a, T: 'a> Iterator for Drain<'a,T> { +impl<'a, T: 'a> Iterator for Drain<'a, T> { type Item = T; #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|reference| unsafe { ptr::read(reference) }) + self.iter + .next() + .map(|reference| unsafe { ptr::read(reference) }) } #[inline] @@ -198,13 +201,15 @@ impl<'a, T: 'a> Iterator for Drain<'a,T> { impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { #[inline] fn next_back(&mut self) -> Option { - self.iter.next_back().map(|reference| unsafe { ptr::read(reference) }) + self.iter + .next_back() + .map(|reference| unsafe { ptr::read(reference) }) } } -impl<'a, T> ExactSizeIterator for Drain<'a, T> { } +impl<'a, T> ExactSizeIterator for Drain<'a, T> {} -impl<'a, T: 'a> Drop for Drain<'a,T> { +impl<'a, T: 'a> Drop for Drain<'a, T> { fn drop(&mut self) { // Destroy the remaining elements. for _ in self.by_ref() {} @@ -232,7 +237,9 @@ impl SmallVecData { SmallVecData { inline } } #[inline] - unsafe fn into_inline(self) -> A { self.inline.assume_init() } + unsafe fn into_inline(self) -> A { + self.inline.assume_init() + } #[inline] unsafe fn heap(&self) -> (*mut A::Item, usize) { (self.heap.0.as_ptr(), self.heap.1) @@ -243,7 +250,9 @@ impl SmallVecData { } #[inline] fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { - SmallVecData { heap: (NonNull::new(ptr).unwrap(), len) } + SmallVecData { + heap: (NonNull::new(ptr).unwrap(), len), + } } } @@ -465,7 +474,6 @@ impl SmallVec { } } - /// Sets the length of a vector. /// /// This will explicitly set the size of the vector, without actually @@ -522,7 +530,11 @@ impl SmallVec { let (ptr, len_ptr) = self.data.heap_mut(); (ptr, len_ptr, self.capacity) } else { - (self.data.inline_mut().as_mut_ptr(), &mut self.capacity, A::size()) + ( + self.data.inline_mut().as_mut_ptr(), + &mut self.capacity, + A::size(), + ) } } } @@ -623,9 +635,10 @@ impl SmallVec { // from callers like insert() let (_, &mut len, cap) = self.triple_mut(); if cap - len < additional { - let new_cap = len.checked_add(additional). - and_then(usize::checked_next_power_of_two). - unwrap_or(usize::max_value()); + let new_cap = len + .checked_add(additional) + .and_then(usize::checked_next_power_of_two) + .unwrap_or(usize::max_value()); self.grow(new_cap); } } @@ -751,15 +764,15 @@ impl SmallVec { /// Insert multiple elements at position `index`, shifting all following elements toward the /// back. - pub fn insert_many>(&mut self, index: usize, iterable: I) { + pub fn insert_many>(&mut self, index: usize, iterable: I) { let iter = iterable.into_iter(); if index == self.len() { return self.extend(iter); } let (lower_size_bound, _) = iter.size_hint(); - assert!(lower_size_bound <= core::isize::MAX as usize); // Ensure offset is indexable - assert!(index + lower_size_bound >= index); // Protect against overflow + assert!(lower_size_bound <= core::isize::MAX as usize); // Ensure offset is indexable + assert!(index + lower_size_bound >= index); // Protect against overflow self.reserve(lower_size_bound); unsafe { @@ -788,7 +801,11 @@ impl SmallVec { } if num_added < lower_size_bound { // Iterator provided fewer elements than the hint - ptr::copy(ptr.offset(lower_size_bound as isize), ptr.offset(num_added as isize), old_len - index); + ptr::copy( + ptr.offset(lower_size_bound as isize), + ptr.offset(num_added as isize), + old_len - index, + ); } self.set_len(old_len + num_added); @@ -845,13 +862,17 @@ impl SmallVec { } /// Removes consecutive duplicate elements. - pub fn dedup(&mut self) where A::Item: PartialEq { + pub fn dedup(&mut self) + where + A::Item: PartialEq, + { self.dedup_by(|a, b| a == b); } /// Removes consecutive duplicate elements using the given equality relation. pub fn dedup_by(&mut self, mut same_bucket: F) - where F: FnMut(&mut A::Item, &mut A::Item) -> bool + where + F: FnMut(&mut A::Item, &mut A::Item) -> bool, { // See the implementation of Vec::dedup_by in the // standard library for an explanation of this algorithm. @@ -882,8 +903,9 @@ impl SmallVec { /// Removes consecutive elements that map to the same key. pub fn dedup_by_key(&mut self, mut key: F) - where F: FnMut(&mut A::Item) -> K, - K: PartialEq + where + F: FnMut(&mut A::Item) -> K, + K: PartialEq, { self.dedup_by(|a, b| key(a) == key(b)); } @@ -956,11 +978,7 @@ impl SmallVec { /// assert_eq!(&*rebuilt, &[4, 5, 6]); /// } /// } - pub unsafe fn from_raw_parts( - ptr: *mut A::Item, - length: usize, - capacity: usize, - ) -> SmallVec { + pub unsafe fn from_raw_parts(ptr: *mut A::Item, length: usize, capacity: usize) -> SmallVec { assert!(capacity > A::size()); SmallVec { capacity, @@ -969,7 +987,10 @@ impl SmallVec { } } -impl SmallVec where A::Item: Copy { +impl SmallVec +where + A::Item: Copy, +{ /// Copy the elements from a slice into a new `SmallVec`. /// /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`. @@ -983,7 +1004,7 @@ impl SmallVec where A::Item: Copy { let slice_mut = &mut *data.as_mut_ptr(); ptr::copy_nonoverlapping(slice.as_ptr(), slice_mut.as_mut_ptr(), len); data - }) + }), } } else { let mut b = slice.to_vec(); @@ -1024,7 +1045,10 @@ impl SmallVec where A::Item: Copy { } } -impl SmallVec where A::Item: Clone { +impl SmallVec +where + A::Item: Clone, +{ /// Resizes the vector so that its length is equal to `len`. /// /// If `len` is less than the current length, the vector simply truncated. @@ -1137,7 +1161,10 @@ impl> io::Write for SmallVec { } #[cfg(feature = "serde")] -impl Serialize for SmallVec where A::Item: Serialize { +impl Serialize for SmallVec +where + A::Item: Serialize, +{ fn serialize(&self, serializer: S) -> Result { let mut state = serializer.serialize_seq(Some(self.len()))?; for item in self { @@ -1148,20 +1175,26 @@ impl Serialize for SmallVec where A::Item: Serialize { } #[cfg(feature = "serde")] -impl<'de, A: Array> Deserialize<'de> for SmallVec where A::Item: Deserialize<'de> { +impl<'de, A: Array> Deserialize<'de> for SmallVec +where + A::Item: Deserialize<'de>, +{ fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_seq(SmallVecVisitor{phantom: PhantomData}) + deserializer.deserialize_seq(SmallVecVisitor { + phantom: PhantomData, + }) } } #[cfg(feature = "serde")] struct SmallVecVisitor { - phantom: PhantomData + phantom: PhantomData, } #[cfg(feature = "serde")] impl<'de, A: Array> Visitor<'de> for SmallVecVisitor -where A::Item: Deserialize<'de>, +where + A::Item: Deserialize<'de>, { type Value = SmallVec; @@ -1170,8 +1203,8 @@ where A::Item: Deserialize<'de>, } fn visit_seq(self, mut seq: B) -> Result - where - B: SeqAccess<'de>, + where + B: SeqAccess<'de>, { let len = seq.size_hint().unwrap_or(0); let mut values = SmallVec::with_capacity(len); @@ -1184,14 +1217,16 @@ where A::Item: Deserialize<'de>, } } - #[cfg(feature = "specialization")] trait SpecFrom { fn spec_from(slice: S) -> SmallVec; } #[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec where A::Item: Clone { +impl<'a, A: Array> SpecFrom for SmallVec +where + A::Item: Clone, +{ #[inline] default fn spec_from(slice: &'a [A::Item]) -> SmallVec { slice.into_iter().cloned().collect() @@ -1199,14 +1234,20 @@ impl<'a, A: Array> SpecFrom for SmallVec where A::Item: Clo } #[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec where A::Item: Copy { +impl<'a, A: Array> SpecFrom for SmallVec +where + A::Item: Copy, +{ #[inline] fn spec_from(slice: &'a [A::Item]) -> SmallVec { SmallVec::from_slice(slice) } } -impl<'a, A: Array> From<&'a [A::Item]> for SmallVec where A::Item: Clone { +impl<'a, A: Array> From<&'a [A::Item]> for SmallVec +where + A::Item: Clone, +{ #[cfg(not(feature = "specialization"))] #[inline] fn from(slice: &'a [A::Item]) -> SmallVec { @@ -1250,7 +1291,7 @@ macro_rules! impl_index { &mut (&mut **self)[index] } } - } + }; } impl_index!(usize, A::Item); @@ -1259,15 +1300,17 @@ impl_index!(ops::RangeFrom, [A::Item]); impl_index!(ops::RangeTo, [A::Item]); impl_index!(ops::RangeFull, [A::Item]); -impl ExtendFromSlice for SmallVec where A::Item: Copy { +impl ExtendFromSlice for SmallVec +where + A::Item: Copy, +{ fn extend_from_slice(&mut self, other: &[A::Item]) { SmallVec::extend_from_slice(self, other) } } - impl FromIterator for SmallVec { - fn from_iter>(iterable: I) -> SmallVec { + fn from_iter>(iterable: I) -> SmallVec { let mut v = SmallVec::new(); v.extend(iterable); v @@ -1275,7 +1318,7 @@ impl FromIterator for SmallVec { } impl Extend for SmallVec { - fn extend>(&mut self, iterable: I) { + fn extend>(&mut self, iterable: I) { let mut iter = iterable.into_iter(); let (lower_size_bound, _) = iter.size_hint(); self.reserve(lower_size_bound); @@ -1299,7 +1342,10 @@ impl Extend for SmallVec { } } -impl fmt::Debug for SmallVec where A::Item: fmt::Debug { +impl fmt::Debug for SmallVec +where + A::Item: fmt::Debug, +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list().entries(self.iter()).finish() } @@ -1340,7 +1386,10 @@ impl Drop for SmallVec { } } -impl Clone for SmallVec where A::Item: Clone { +impl Clone for SmallVec +where + A::Item: Clone, +{ fn clone(&self) -> SmallVec { let mut new_vector = SmallVec::with_capacity(self.len()); for element in self.iter() { @@ -1351,30 +1400,45 @@ impl Clone for SmallVec where A::Item: Clone { } impl PartialEq> for SmallVec - where A::Item: PartialEq { +where + A::Item: PartialEq, +{ #[inline] - fn eq(&self, other: &SmallVec) -> bool { self[..] == other[..] } + fn eq(&self, other: &SmallVec) -> bool { + self[..] == other[..] + } #[inline] - fn ne(&self, other: &SmallVec) -> bool { self[..] != other[..] } + fn ne(&self, other: &SmallVec) -> bool { + self[..] != other[..] + } } impl Eq for SmallVec where A::Item: Eq {} -impl PartialOrd for SmallVec where A::Item: PartialOrd { +impl PartialOrd for SmallVec +where + A::Item: PartialOrd, +{ #[inline] fn partial_cmp(&self, other: &SmallVec) -> Option { PartialOrd::partial_cmp(&**self, &**other) } } -impl Ord for SmallVec where A::Item: Ord { +impl Ord for SmallVec +where + A::Item: Ord, +{ #[inline] fn cmp(&self, other: &SmallVec) -> cmp::Ordering { Ord::cmp(&**self, &**other) } } -impl Hash for SmallVec where A::Item: Hash { +impl Hash for SmallVec +where + A::Item: Hash, +{ fn hash(&self, state: &mut H) { (**self).hash(state) } @@ -1395,7 +1459,7 @@ pub struct IntoIter { impl Drop for IntoIter { fn drop(&mut self) { - for _ in self { } + for _ in self {} } } @@ -1406,8 +1470,7 @@ impl Iterator for IntoIter { fn next(&mut self) -> Option { if self.current == self.end { None - } - else { + } else { unsafe { let current = self.current as isize; self.current += 1; @@ -1428,8 +1491,7 @@ impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { if self.current == self.end { None - } - else { + } else { unsafe { self.end -= 1; Some(ptr::read(self.data.as_ptr().offset(self.end as isize))) @@ -1438,7 +1500,7 @@ impl DoubleEndedIterator for IntoIter { } } -impl ExactSizeIterator for IntoIter { } +impl ExactSizeIterator for IntoIter {} impl IntoIterator for SmallVec { type IntoIter = IntoIter; @@ -1496,7 +1558,10 @@ struct SetLenOnDrop<'a> { impl<'a> SetLenOnDrop<'a> { #[inline] fn new(len: &'a mut usize) -> Self { - SetLenOnDrop { local_len: *len, len: len } + SetLenOnDrop { + local_len: *len, + len: len, + } } #[inline] @@ -1530,19 +1595,18 @@ macro_rules! impl_array( } ); -impl_array!(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, - 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, - 0x10000, 0x20000, 0x40000, 0x80000, 0x100000); +impl_array!( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100, + 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, + 0x100000 +); #[cfg(test)] mod tests { extern crate alloc; use crate::SmallVec; - use alloc::{ - rc::Rc, - boxed::Box, - }; + use alloc::{boxed::Box, rc::Rc}; use core::iter::FromIterator; #[test] @@ -1561,10 +1625,7 @@ mod tests { let mut v = SmallVec::<[_; 16]>::new(); v.push("hello"); v.push("there"); - assert_eq!(&*v, &[ - "hello", - "there", - ][..]); + assert_eq!(&*v, &["hello", "there",][..]); } #[test] @@ -1576,12 +1637,7 @@ mod tests { v.push("burma"); assert_eq!(v[0], "hello"); v.push("shave"); - assert_eq!(&*v, &[ - "hello", - "there", - "burma", - "shave", - ][..]); + assert_eq!(&*v, &["hello", "there", "burma", "shave",][..]); } #[test] @@ -1595,16 +1651,10 @@ mod tests { v.push("there"); v.push("burma"); v.push("shave"); - assert_eq!(&*v, &[ - "hello", - "there", - "burma", - "shave", - "hello", - "there", - "burma", - "shave", - ][..]); + assert_eq!( + &*v, + &["hello", "there", "burma", "shave", "hello", "there", "burma", "shave",][..] + ); } /// https://github.com/servo/rust-smallvec/issues/4 @@ -1785,14 +1835,24 @@ mod tests { } assert_eq!(v.len(), 4); v.insert_many(1, [5, 6].iter().cloned()); - assert_eq!(&v.iter().map(|v| *v).collect::>(), &[0, 5, 6, 1, 2, 3]); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); } - struct MockHintIter{x: T, hint: usize} + struct MockHintIter { + x: T, + hint: usize, + } impl Iterator for MockHintIter { type Item = T::Item; - fn next(&mut self) -> Option {self.x.next()} - fn size_hint(&self) -> (usize, Option) {(self.hint, None)} + fn next(&mut self) -> Option { + self.x.next() + } + fn size_hint(&self) -> (usize, Option) { + (self.hint, None) + } } #[test] @@ -1802,8 +1862,17 @@ mod tests { v.push(x); } assert_eq!(v.len(), 4); - v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 5}); - assert_eq!(&v.iter().map(|v| *v).collect::>(), &[0, 5, 6, 1, 2, 3]); + v.insert_many( + 1, + MockHintIter { + x: [5, 6].iter().cloned(), + hint: 5, + }, + ); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); } #[test] @@ -1813,8 +1882,17 @@ mod tests { v.push(x); } assert_eq!(v.len(), 4); - v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 1}); - assert_eq!(&v.iter().map(|v| *v).collect::>(), &[0, 5, 6, 1, 2, 3]); + v.insert_many( + 1, + MockHintIter { + x: [5, 6].iter().cloned(), + hint: 1, + }, + ); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); } #[cfg(feature = "std")] @@ -1822,7 +1900,7 @@ mod tests { // https://github.com/servo/rust-smallvec/issues/96 fn test_insert_many_panic() { struct PanicOnDoubleDrop { - dropped: Box + dropped: Box, } impl Drop for PanicOnDoubleDrop { @@ -1835,14 +1913,23 @@ mod tests { struct BadIter; impl Iterator for BadIter { type Item = PanicOnDoubleDrop; - fn size_hint(&self) -> (usize, Option) { (1, None) } - fn next(&mut self) -> Option { panic!() } + fn size_hint(&self) -> (usize, Option) { + (1, None) + } + fn next(&mut self) -> Option { + panic!() + } } let mut vec: SmallVec<[PanicOnDoubleDrop; 0]> = vec![ - PanicOnDoubleDrop { dropped: Box::new(false) }, - PanicOnDoubleDrop { dropped: Box::new(false) }, - ].into(); + PanicOnDoubleDrop { + dropped: Box::new(false), + }, + PanicOnDoubleDrop { + dropped: Box::new(false), + }, + ] + .into(); let result = ::std::panic::catch_unwind(move || { vec.insert_many(0, BadIter); }); @@ -1865,7 +1952,10 @@ mod tests { } assert_eq!(v.len(), 4); v.insert_from_slice(1, &[5, 6]); - assert_eq!(&v.iter().map(|v| *v).collect::>(), &[0, 5, 6, 1, 2, 3]); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); } #[test] @@ -1876,7 +1966,10 @@ mod tests { } assert_eq!(v.len(), 4); v.extend_from_slice(&[5, 6]); - assert_eq!(&v.iter().map(|v| *v).collect::>(), &[0, 1, 2, 3, 5, 6]); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 1, 2, 3, 5, 6] + ); } #[test] @@ -1938,8 +2031,8 @@ mod tests { #[cfg(feature = "std")] #[test] fn test_hash() { - use std::hash::Hash; use std::collections::hash_map::DefaultHasher; + use std::hash::Hash; { let mut a: SmallVec<[u32; 2]> = SmallVec::new(); @@ -2043,7 +2136,10 @@ mod tests { #[test] fn test_from_slice() { assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1][..])[..], [1]); - assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], [1, 2, 3]); + assert_eq!( + &SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], + [1, 2, 3] + ); } #[test] From ef7c3288ab879bf051c43b34834fd4b333e3bc0d Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 21:36:27 -0300 Subject: [PATCH 10/24] Splits the lib.rs file --- Cargo.toml | 6 +- benches/bench.rs | 4 +- lib.rs | 2361 -------------------------------------- src/array.rs | 30 + src/drain.rs | 44 + src/extend_from_slice.rs | 29 + src/into_iter.rs | 60 + src/lib.rs | 59 + src/macros.rs | 71 ++ src/set_len_on_drop.rs | 34 + src/small_vec.rs | 1160 +++++++++++++++++++ src/small_vec_data.rs | 99 ++ src/small_vec_visitor.rs | 36 + src/spec_from.rs | 7 + src/tests.rs | 753 ++++++++++++ src/utils.rs | 17 + 16 files changed, 2402 insertions(+), 2368 deletions(-) delete mode 100644 lib.rs create mode 100644 src/array.rs create mode 100644 src/drain.rs create mode 100644 src/extend_from_slice.rs create mode 100644 src/into_iter.rs create mode 100644 src/lib.rs create mode 100644 src/macros.rs create mode 100644 src/set_len_on_drop.rs create mode 100644 src/small_vec.rs create mode 100644 src/small_vec_data.rs create mode 100644 src/small_vec_visitor.rs create mode 100644 src/spec_from.rs create mode 100644 src/tests.rs create mode 100644 src/utils.rs diff --git a/Cargo.toml b/Cargo.toml index 660806a..b875416 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,4 @@ const_generics = [] may_dangle = [] specialization = [] std = [] -union = [] - -[lib] -name = "smallvec" -path = "lib.rs" \ No newline at end of file +union = [] \ No newline at end of file diff --git a/benches/bench.rs b/benches/bench.rs index 058c530..91f3649 100644 --- a/benches/bench.rs +++ b/benches/bench.rs @@ -2,8 +2,8 @@ extern crate test; -use test::Bencher; use smallvec::{smallvec, ExtendFromSlice, SmallVec}; +use test::Bencher; const VEC_SIZE: usize = 16; const SPILLED_SIZE: usize = 100; @@ -294,4 +294,4 @@ fn bench_macro_from_list_vec(b: &mut Bencher) { ]; vec }); -} \ No newline at end of file +} diff --git a/lib.rs b/lib.rs deleted file mode 100644 index 52f40c4..0000000 --- a/lib.rs +++ /dev/null @@ -1,2361 +0,0 @@ -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! 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. -//! -//! ## no_std support -//! -//! By default, `smallvec` depends on `libstd`. However, it can be configured to use the unstable -//! `liballoc` API instead, for use on platforms that have `liballoc` but not `libstd`. This -//! configuration is currently unstable and is not guaranteed to work on all versions of Rust. -//! -//! To depend on `smallvec` without `libstd`, use `default-features = false` in the `smallvec` -//! section of Cargo.toml to disable its `"std"` feature. -//! -//! ## `union` feature -//! -//! When the `union` feature is enabled `smallvec` will track its state (inline or spilled) -//! without the use of an enum tag, reducing the size of the `smallvec` by one machine word. -//! This means that there is potentially no space overhead compared to `Vec`. -//! Note that `smallvec` can still be larger than `Vec` if the inline buffer is larger than two -//! machine words. -//! -//! To use this feature add `features = ["union"]` in the `smallvec` section of Cargo.toml. -//! Note that this feature requires a nightly compiler (for now). - -#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] -#![cfg_attr(feature = "specialization", feature(specialization))] -#![cfg_attr(feature = "union", feature(untagged_unions))] -#![deny(missing_docs)] - -use core::{ - borrow::{Borrow, BorrowMut}, - cmp, fmt, - hash::{Hash, Hasher}, - iter::{repeat, FromIterator, IntoIterator}, - mem::{self, MaybeUninit}, - ops, - ptr::{self, NonNull}, - slice, -}; -#[cfg(feature = "std")] -use std::io; -#[cfg(feature = "serde")] -use { - core::marker::PhantomData, - serde::{ - de::{Deserialize, Deserializer, SeqAccess, Visitor}, - ser::{Serialize, SerializeSeq, Serializer}, - }, -}; - -/// Creates a [`SmallVec`] containing the arguments. -/// -/// `smallvec!` allows `SmallVec`s to be defined with the same syntax as array expressions. -/// There are two forms of this macro: -/// -/// - Create a [`SmallVec`] containing a given list of elements: -/// -/// ``` -/// # #[macro_use] extern crate smallvec; -/// # use smallvec::SmallVec; -/// # fn main() { -/// let v: SmallVec<[_; 128]> = smallvec![1, 2, 3]; -/// assert_eq!(v[0], 1); -/// assert_eq!(v[1], 2); -/// assert_eq!(v[2], 3); -/// # } -/// ``` -/// -/// - Create a [`SmallVec`] from a given element and size: -/// -/// ``` -/// # #[macro_use] extern crate smallvec; -/// # use smallvec::SmallVec; -/// # fn main() { -/// let v: SmallVec<[_; 0x8000]> = smallvec![1; 3]; -/// assert_eq!(v, SmallVec::from_buf([1, 1, 1])); -/// # } -/// ``` -/// -/// Note that unlike array expressions this syntax supports all elements -/// which implement [`Clone`] and the number of elements doesn't have to be -/// a constant. -/// -/// This will use `clone` to duplicate an expression, so one should be careful -/// using this with types having a nonstandard `Clone` implementation. For -/// example, `smallvec![Rc::new(1); 5]` will create a vector of five references -/// to the same boxed integer value, not five references pointing to independently -/// boxed integers. - -#[macro_export] -macro_rules! smallvec { - // count helper: transform any expression into 1 - (@one $x:expr) => (1usize); - ($elem:expr; $n:expr) => ({ - $crate::SmallVec::from_elem($elem, $n) - }); - ($($x:expr),*$(,)*) => ({ - let count = 0usize $(+ smallvec!(@one $x))*; - let mut vec = $crate::SmallVec::new(); - if count <= vec.inline_size() { - $(vec.push($x);)* - vec - } else { - $crate::SmallVec::from_vec(vec![$($x,)*]) - } - }); -} - -/// Hint to the optimizer that any code path which calls this function is -/// statically unreachable and can be removed. -/// -/// Equivalent to `std::hint::unreachable_unchecked` but works in older versions of Rust. -#[inline] -pub unsafe fn unreachable() -> ! { - enum Void {} - let x: &Void = mem::transmute(1usize); - match *x {} -} - -/// `panic!()` in debug builds, optimization hint in release. -#[cfg(not(feature = "union"))] -macro_rules! debug_unreachable { - () => { - debug_unreachable!("entered unreachable code") - }; - ($e:expr) => { - if cfg!(not(debug_assertions)) { - unreachable(); - } else { - panic!($e); - } - }; -} - -/// Trait to be implemented by a collection that can be extended from a slice -/// -/// ## Example -/// -/// ```rust -/// use smallvec::{ExtendFromSlice, SmallVec}; -/// -/// fn initialize>(v: &mut V) { -/// v.extend_from_slice(b"Test!"); -/// } -/// -/// let mut vec = Vec::new(); -/// initialize(&mut vec); -/// assert_eq!(&vec, b"Test!"); -/// -/// let mut small_vec = SmallVec::<[u8; 8]>::new(); -/// initialize(&mut small_vec); -/// assert_eq!(&small_vec as &[_], b"Test!"); -/// ``` -pub trait ExtendFromSlice { - /// Extends a collection from a slice of its element type - fn extend_from_slice(&mut self, other: &[T]); -} - -impl ExtendFromSlice for Vec { - fn extend_from_slice(&mut self, other: &[T]) { - Vec::extend_from_slice(self, other) - } -} - -unsafe fn deallocate(ptr: *mut T, capacity: usize) { - let _vec: Vec = Vec::from_raw_parts(ptr, 0, capacity); - // Let it drop. -} - -/// An iterator that removes the items from a `SmallVec` and yields them by value. -/// -/// Returned from [`SmallVec::drain`][1]. -/// -/// [1]: struct.SmallVec.html#method.drain -pub struct Drain<'a, T: 'a> { - iter: slice::IterMut<'a, T>, -} - -impl<'a, T: 'a> Iterator for Drain<'a, T> { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - self.iter - .next() - .map(|reference| unsafe { ptr::read(reference) }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { - #[inline] - fn next_back(&mut self) -> Option { - self.iter - .next_back() - .map(|reference| unsafe { ptr::read(reference) }) - } -} - -impl<'a, T> ExactSizeIterator for Drain<'a, T> {} - -impl<'a, T: 'a> Drop for Drain<'a, T> { - fn drop(&mut self) { - // Destroy the remaining elements. - for _ in self.by_ref() {} - } -} - -#[cfg(feature = "union")] -union SmallVecData { - inline: MaybeUninit, - heap: (NonNull, usize), -} - -#[cfg(feature = "union")] -impl SmallVecData { - #[inline] - unsafe fn inline(&self) -> &A { - &*self.inline.as_ptr() - } - #[inline] - unsafe fn inline_mut(&mut self) -> &mut A { - &mut *self.inline.as_mut_ptr() - } - #[inline] - fn from_inline(inline: MaybeUninit) -> SmallVecData { - SmallVecData { inline } - } - #[inline] - unsafe fn into_inline(self) -> A { - self.inline.assume_init() - } - #[inline] - unsafe fn heap(&self) -> (*mut A::Item, usize) { - (self.heap.0.as_ptr(), self.heap.1) - } - #[inline] - unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { - (self.heap.0.as_ptr(), &mut self.heap.1) - } - #[inline] - fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { - SmallVecData { - heap: (NonNull::new(ptr).unwrap(), len), - } - } -} - -#[cfg(not(feature = "union"))] -enum SmallVecData { - Inline(MaybeUninit), - Heap((NonNull, usize)), -} - -#[cfg(not(feature = "union"))] -impl SmallVecData { - #[inline] - unsafe fn inline(&self) -> &A { - match *self { - SmallVecData::Inline(ref a) => &*a.as_ptr(), - _ => debug_unreachable!(), - } - } - #[inline] - unsafe fn inline_mut(&mut self) -> &mut A { - match *self { - SmallVecData::Inline(ref mut a) => &mut *a.as_mut_ptr(), - _ => debug_unreachable!(), - } - } - #[inline] - fn from_inline(inline: MaybeUninit) -> SmallVecData { - SmallVecData::Inline(inline) - } - #[inline] - unsafe fn into_inline(self) -> A { - match self { - SmallVecData::Inline(a) => a.assume_init(), - _ => debug_unreachable!(), - } - } - #[inline] - unsafe fn heap(&self) -> (*mut A::Item, usize) { - match *self { - SmallVecData::Heap(data) => (data.0.as_ptr(), data.1), - _ => debug_unreachable!(), - } - } - #[inline] - unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { - match *self { - SmallVecData::Heap(ref mut data) => (data.0.as_ptr(), &mut data.1), - _ => debug_unreachable!(), - } - } - #[inline] - fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { - SmallVecData::Heap((NonNull::new(ptr).unwrap(), len)) - } -} - -unsafe impl Send for SmallVecData {} -unsafe impl Sync for SmallVecData {} - -/// 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. -/// -/// ## Example -/// -/// ```rust -/// use smallvec::SmallVec; -/// let mut v = SmallVec::<[u8; 4]>::new(); // initialize an empty vector -/// -/// // The vector 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 { - // The capacity field is used to determine which of the storage variants is active: - // If capacity <= A::size() then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use). - // If capacity > A::size() then the heap variant is used and capacity holds the size of the memory allocation. - capacity: usize, - data: SmallVecData, -} - -impl SmallVec { - /// Construct an empty vector - #[inline] - pub fn new() -> SmallVec { - unsafe { - SmallVec { - capacity: 0, - data: SmallVecData::from_inline(mem::uninitialized()), - } - } - } - - /// Construct an empty vector with enough capacity pre-allocated to store at least `n` - /// elements. - /// - /// Will create a heap allocation only if `n` is larger than the inline capacity. - /// - /// ``` - /// # use smallvec::SmallVec; - /// - /// let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(100); - /// - /// assert!(v.is_empty()); - /// assert!(v.capacity() >= 100); - /// ``` - #[inline] - pub fn with_capacity(n: usize) -> Self { - let mut v = SmallVec::new(); - v.reserve_exact(n); - v - } - - /// Construct a new `SmallVec` from a `Vec`. - /// - /// Elements will be copied to the inline buffer if vec.capacity() <= A::size(). - /// - /// ```rust - /// use smallvec::SmallVec; - /// - /// let vec = vec![1, 2, 3, 4, 5]; - /// let small_vec: SmallVec<[_; 3]> = SmallVec::from_vec(vec); - /// - /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - /// ``` - #[inline] - pub fn from_vec(mut vec: Vec) -> SmallVec { - if vec.capacity() <= A::size() { - unsafe { - let mut data = SmallVecData::::from_inline(mem::uninitialized()); - let len = vec.len(); - vec.set_len(0); - ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().as_mut_ptr(), len); - - SmallVec { - capacity: len, - data, - } - } - } else { - let (ptr, cap, len) = (vec.as_mut_ptr(), vec.capacity(), vec.len()); - mem::forget(vec); - - SmallVec { - capacity: cap, - data: SmallVecData::from_heap(ptr, len), - } - } - } - - /// Constructs a new `SmallVec` on the stack from an `A` without - /// copying elements. - /// - /// ```rust - /// use smallvec::SmallVec; - /// - /// let buf = [1, 2, 3, 4, 5]; - /// let small_vec: SmallVec<_> = SmallVec::from_buf(buf); - /// - /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - /// ``` - #[inline] - pub fn from_buf(buf: A) -> SmallVec { - SmallVec { - capacity: A::size(), - data: SmallVecData::from_inline(MaybeUninit::new(buf)), - } - } - - /// Constructs a new `SmallVec` on the stack from an `A` without - /// copying elements. Also sets the length, which must be less or - /// equal to the size of `buf`. - /// - /// ```rust - /// use smallvec::SmallVec; - /// - /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; - /// let small_vec: SmallVec<_> = SmallVec::from_buf_and_len(buf, 5); - /// - /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - /// ``` - #[inline] - pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec { - assert!(len <= A::size()); - unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) } - } - - /// Constructs a new `SmallVec` on the stack from an `A` without - /// copying elements. Also sets the length. The user is responsible - /// for ensuring that `len <= A::size()`. - /// - /// ```rust - /// use smallvec::SmallVec; - /// - /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; - /// let small_vec: SmallVec<_> = unsafe { - /// SmallVec::from_buf_and_len_unchecked(buf, 5) - /// }; - /// - /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - /// ``` - #[inline] - pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec { - SmallVec { - capacity: len, - data: SmallVecData::from_inline(MaybeUninit::new(buf)), - } - } - - /// 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) { - let (_, len_ptr, _) = self.triple_mut(); - *len_ptr = 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.triple().1 - } - - /// 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 { - self.triple().2 - } - - /// Returns a tuple with (data ptr, len, capacity) - /// Useful to get all SmallVec properties with a single check of the current storage variant. - #[inline] - fn triple(&self) -> (*const A::Item, usize, usize) { - unsafe { - if self.spilled() { - let (ptr, len) = self.data.heap(); - (ptr, len, self.capacity) - } else { - (self.data.inline().as_ptr(), self.capacity, A::size()) - } - } - } - - /// Returns a tuple with (data ptr, len ptr, capacity) - #[inline] - fn triple_mut(&mut self) -> (*mut A::Item, &mut usize, usize) { - unsafe { - if self.spilled() { - let (ptr, len_ptr) = self.data.heap_mut(); - (ptr, len_ptr, self.capacity) - } else { - ( - self.data.inline_mut().as_mut_ptr(), - &mut self.capacity, - A::size(), - ) - } - } - } - - /// Returns `true` if the data has spilled into a separate heap-allocated buffer. - #[inline] - pub fn spilled(&self) -> bool { - self.capacity > A::size() - } - - /// Empty the vector and return an iterator over its former contents. - pub fn drain(&mut self) -> Drain { - unsafe { - let ptr = self.as_mut_ptr(); - - let current_len = self.len(); - self.set_len(0); - - let slice = slice::from_raw_parts_mut(ptr, current_len); - - Drain { - iter: slice.iter_mut(), - } - } - } - - /// Append an item to the vector. - #[inline] - pub fn push(&mut self, value: A::Item) { - unsafe { - let (_, &mut len, cap) = self.triple_mut(); - if len == cap { - self.reserve(1); - } - let (ptr, len_ptr, _) = self.triple_mut(); - *len_ptr = len + 1; - ptr::write(ptr.offset(len as isize), value); - } - } - - /// Remove an item from the end of the vector and return it, or None if empty. - #[inline] - pub fn pop(&mut self) -> Option { - unsafe { - let (ptr, len_ptr, _) = self.triple_mut(); - if *len_ptr == 0 { - return None; - } - let last_index = *len_ptr - 1; - *len_ptr = last_index; - Some(ptr::read(ptr.offset(last_index as isize))) - } - } - - /// Re-allocate to set the capacity to `max(new_cap, inline_size())`. - /// - /// Panics if `new_cap` is less than the vector's length. - pub fn grow(&mut self, new_cap: usize) { - unsafe { - let (ptr, &mut len, cap) = self.triple_mut(); - let unspilled = !self.spilled(); - assert!(new_cap >= len); - if new_cap <= self.inline_size() { - if unspilled { - return; - } - self.data = SmallVecData::from_inline(mem::uninitialized()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); - self.capacity = len; - } else if new_cap != cap { - let mut vec = Vec::with_capacity(new_cap); - let new_alloc = vec.as_mut_ptr(); - mem::forget(vec); - ptr::copy_nonoverlapping(ptr, new_alloc, len); - self.data = SmallVecData::from_heap(new_alloc, len); - self.capacity = new_cap; - if unspilled { - return; - } - } else { - return; - } - deallocate(ptr, cap); - } - } - - /// 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.) - #[inline] - pub fn reserve(&mut self, additional: usize) { - // prefer triple_mut() even if triple() would work - // so that the optimizer removes duplicated calls to it - // from callers like insert() - let (_, &mut len, cap) = self.triple_mut(); - if cap - len < additional { - let new_cap = len - .checked_add(additional) - .and_then(usize::checked_next_power_of_two) - .unwrap_or(usize::max_value()); - self.grow(new_cap); - } - } - - /// Reserve the minimum capacity for `additional` more elements to be inserted. - /// - /// Panics if the new capacity overflows `usize`. - pub fn reserve_exact(&mut self, additional: usize) { - let (_, &mut len, cap) = self.triple_mut(); - if cap - len < additional { - match len.checked_add(additional) { - Some(cap) => self.grow(cap), - None => panic!("reserve_exact overflow"), - } - } - } - - /// 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) { - if !self.spilled() { - return; - } - let len = self.len(); - if self.inline_size() >= len { - unsafe { - let (ptr, len) = self.data.heap(); - self.data = SmallVecData::from_inline(mem::uninitialized()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); - deallocate(ptr, self.capacity); - self.capacity = len; - } - } 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) { - unsafe { - let (ptr, len_ptr, _) = self.triple_mut(); - while len < *len_ptr { - let last_index = *len_ptr - 1; - *len_ptr = last_index; - ptr::drop_in_place(ptr.offset(last_index as isize)); - } - } - } - - /// Extracts a slice containing the entire vector. - /// - /// Equivalent to `&s[..]`. - pub fn as_slice(&self) -> &[A::Item] { - self - } - - /// Extracts a mutable slice of the entire vector. - /// - /// Equivalent to `&mut s[..]`. - pub fn as_mut_slice(&mut self) -> &mut [A::Item] { - self - } - - /// 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_or_else(|| unsafe { unreachable() }) - } - - /// 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 { - unsafe { - let (mut ptr, len_ptr, _) = self.triple_mut(); - let len = *len_ptr; - assert!(index < len); - *len_ptr = len - 1; - ptr = ptr.offset(index as isize); - let item = ptr::read(ptr); - ptr::copy(ptr.offset(1), ptr, len - index - 1); - item - } - } - - /// 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); - - unsafe { - let (mut ptr, len_ptr, _) = self.triple_mut(); - let len = *len_ptr; - assert!(index <= len); - *len_ptr = len + 1; - ptr = ptr.offset(index as isize); - ptr::copy(ptr, ptr.offset(1), len - index); - ptr::write(ptr, element); - } - } - - /// Insert multiple elements at position `index`, shifting all following elements toward the - /// back. - pub fn insert_many>(&mut self, index: usize, iterable: I) { - let iter = iterable.into_iter(); - if index == self.len() { - return self.extend(iter); - } - - let (lower_size_bound, _) = iter.size_hint(); - assert!(lower_size_bound <= core::isize::MAX as usize); // Ensure offset is indexable - assert!(index + lower_size_bound >= index); // Protect against overflow - self.reserve(lower_size_bound); - - unsafe { - let old_len = self.len(); - assert!(index <= old_len); - let mut ptr = self.as_mut_ptr().offset(index as isize); - - // Move the trailing elements. - ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index); - - // In case the iterator panics, don't double-drop the items we just copied above. - self.set_len(index); - - let mut num_added = 0; - for element in iter { - let mut cur = ptr.offset(num_added as isize); - if num_added >= lower_size_bound { - // Iterator provided more elements than the hint. Move trailing items again. - self.reserve(1); - ptr = self.as_mut_ptr().offset(index as isize); - cur = ptr.offset(num_added as isize); - ptr::copy(cur, cur.offset(1), old_len - index); - } - ptr::write(cur, element); - num_added += 1; - } - if num_added < lower_size_bound { - // Iterator provided fewer elements than the hint - ptr::copy( - ptr.offset(lower_size_bound as isize), - ptr.offset(num_added as isize), - old_len - index, - ); - } - - self.set_len(old_len + num_added); - } - } - - /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto - /// the heap. - pub fn into_vec(self) -> Vec { - if self.spilled() { - unsafe { - let (ptr, len) = self.data.heap(); - let v = Vec::from_raw_parts(ptr, len, self.capacity); - mem::forget(self); - v - } - } else { - self.into_iter().collect() - } - } - - /// Convert the SmallVec into an `A` if possible. Otherwise return `Err(Self)`. - /// - /// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements), - /// or if the SmallVec is too long (and all the elements were spilled to the heap). - pub fn into_inner(self) -> Result { - if self.spilled() || self.len() != A::size() { - Err(self) - } else { - unsafe { - let data = ptr::read(&self.data); - mem::forget(self); - Ok(data.into_inline()) - } - } - } - - /// Retains only the elements specified by the predicate. - /// - /// In other words, remove all elements `e` such that `f(&e)` returns `false`. - /// This method operates in place and preserves the order of the retained - /// elements. - pub fn retain bool>(&mut self, mut f: F) { - let mut del = 0; - let len = self.len(); - for i in 0..len { - if !f(&mut self[i]) { - del += 1; - } else if del > 0 { - self.swap(i - del, i); - } - } - self.truncate(len - del); - } - - /// Removes consecutive duplicate elements. - pub fn dedup(&mut self) - where - A::Item: PartialEq, - { - self.dedup_by(|a, b| a == b); - } - - /// Removes consecutive duplicate elements using the given equality relation. - pub fn dedup_by(&mut self, mut same_bucket: F) - where - F: FnMut(&mut A::Item, &mut A::Item) -> bool, - { - // See the implementation of Vec::dedup_by in the - // standard library for an explanation of this algorithm. - let len = self.len(); - if len <= 1 { - return; - } - - let ptr = self.as_mut_ptr(); - let mut w: usize = 1; - - unsafe { - for r in 1..len { - let p_r = ptr.offset(r as isize); - let p_wm1 = ptr.offset((w - 1) as isize); - if !same_bucket(&mut *p_r, &mut *p_wm1) { - if r != w { - let p_w = p_wm1.offset(1); - mem::swap(&mut *p_r, &mut *p_w); - } - w += 1; - } - } - } - - self.truncate(w); - } - - /// Removes consecutive elements that map to the same key. - pub fn dedup_by_key(&mut self, mut key: F) - where - F: FnMut(&mut A::Item) -> K, - K: PartialEq, - { - self.dedup_by(|a, b| key(a) == key(b)); - } - - /// Creates a `SmallVec` directly from the raw components of another - /// `SmallVec`. - /// - /// # Safety - /// - /// This is highly unsafe, due to the number of invariants that aren't - /// checked: - /// - /// * `ptr` needs to have been previously allocated via `SmallVec` for its - /// spilled storage (at least, it's highly likely to be incorrect if it - /// wasn't). - /// * `ptr`'s `A::Item` type needs to be the same size and alignment that - /// it was allocated with - /// * `length` needs to be less than or equal to `capacity`. - /// * `capacity` needs to be the capacity that the pointer was allocated - /// with. - /// - /// Violating these may cause problems like corrupting the allocator's - /// internal data structures. - /// - /// Additionally, `capacity` must be greater than the amount of inline - /// storage `A` has; that is, the new `SmallVec` must need to spill over - /// into heap allocated storage. This condition is asserted against. - /// - /// The ownership of `ptr` is effectively transferred to the - /// `SmallVec` which may then deallocate, reallocate or change the - /// contents of memory pointed to by the pointer at will. Ensure - /// that nothing else uses the pointer after calling this - /// function. - /// - /// # Examples - /// - /// ``` - /// # #[macro_use] extern crate smallvec; - /// # use smallvec::SmallVec; - /// use std::mem; - /// use std::ptr; - /// - /// fn main() { - /// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3]; - /// - /// // Pull out the important parts of `v`. - /// let p = v.as_mut_ptr(); - /// let len = v.len(); - /// let cap = v.capacity(); - /// let spilled = v.spilled(); - /// - /// unsafe { - /// // Forget all about `v`. The heap allocation that stored the - /// // three values won't be deallocated. - /// mem::forget(v); - /// - /// // Overwrite memory with [4, 5, 6]. - /// // - /// // This is only safe if `spilled` is true! Otherwise, we are - /// // writing into the old `SmallVec`'s inline storage on the - /// // stack. - /// assert!(spilled); - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); - /// } - /// - /// // Put everything back together into a SmallVec with a different - /// // amount of inline storage, but which is still less than `cap`. - /// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap); - /// assert_eq!(&*rebuilt, &[4, 5, 6]); - /// } - /// } - pub unsafe fn from_raw_parts(ptr: *mut A::Item, length: usize, capacity: usize) -> SmallVec { - assert!(capacity > A::size()); - SmallVec { - capacity, - data: SmallVecData::from_heap(ptr, length), - } - } -} - -impl SmallVec -where - A::Item: Copy, -{ - /// Copy the elements from a slice into a new `SmallVec`. - /// - /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`. - pub fn from_slice(slice: &[A::Item]) -> Self { - let len = slice.len(); - if len <= A::size() { - SmallVec { - capacity: len, - data: SmallVecData::from_inline(unsafe { - let mut data = MaybeUninit::::uninit(); - let slice_mut = &mut *data.as_mut_ptr(); - ptr::copy_nonoverlapping(slice.as_ptr(), slice_mut.as_mut_ptr(), len); - data - }), - } - } else { - let mut b = slice.to_vec(); - let (ptr, cap) = (b.as_mut_ptr(), b.capacity()); - mem::forget(b); - SmallVec { - capacity: cap, - data: SmallVecData::from_heap(ptr, len), - } - } - } - /// Copy elements from a slice into the vector at position `index`, shifting any following - /// elements toward the back. - /// - /// For slices of `Copy` types, this is more efficient than `insert`. - pub fn insert_from_slice(&mut self, index: usize, slice: &[A::Item]) { - self.reserve(slice.len()); - - let len = self.len(); - assert!(index <= len); - - unsafe { - let slice_ptr = slice.as_ptr(); - let ptr = self.as_mut_ptr().offset(index as isize); - ptr::copy(ptr, ptr.offset(slice.len() as isize), len - index); - ptr::copy_nonoverlapping(slice_ptr, ptr, slice.len()); - self.set_len(len + slice.len()); - } - } - - /// Copy elements from a slice and append them to the vector. - /// - /// For slices of `Copy` types, this is more efficient than `extend`. - #[inline] - pub fn extend_from_slice(&mut self, slice: &[A::Item]) { - let len = self.len(); - self.insert_from_slice(len, slice); - } -} - -impl SmallVec -where - A::Item: Clone, -{ - /// Resizes the vector so that its length is equal to `len`. - /// - /// If `len` is less than the current length, the vector simply truncated. - /// - /// If `len` is greater than the current length, `value` is appended to the - /// vector until its length equals `len`. - pub fn resize(&mut self, len: usize, value: A::Item) { - let old_len = self.len(); - - if len > old_len { - self.extend(repeat(value).take(len - old_len)); - } else { - self.truncate(len); - } - } - - /// Creates a `SmallVec` with `n` copies of `elem`. - /// ``` - /// use smallvec::SmallVec; - /// - /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); - /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); - /// ``` - pub fn from_elem(elem: A::Item, n: usize) -> Self { - if n > A::size() { - vec![elem; n].into() - } else { - let mut v = SmallVec::::new(); - unsafe { - let (ptr, len_ptr, _) = v.triple_mut(); - let mut local_len = SetLenOnDrop::new(len_ptr); - - for i in 0..n as isize { - core::ptr::write(ptr.offset(i), elem.clone()); - local_len.increment_len(1); - } - } - v - } - } -} - -impl ops::Deref for SmallVec { - type Target = [A::Item]; - #[inline] - fn deref(&self) -> &[A::Item] { - unsafe { - let (ptr, len, _) = self.triple(); - slice::from_raw_parts(ptr, len) - } - } -} - -impl ops::DerefMut for SmallVec { - #[inline] - fn deref_mut(&mut self) -> &mut [A::Item] { - unsafe { - let (ptr, &mut len, _) = self.triple_mut(); - slice::from_raw_parts_mut(ptr, len) - } - } -} - -impl AsRef<[A::Item]> for SmallVec { - #[inline] - fn as_ref(&self) -> &[A::Item] { - self - } -} - -impl AsMut<[A::Item]> for SmallVec { - #[inline] - fn as_mut(&mut self) -> &mut [A::Item] { - self - } -} - -impl Borrow<[A::Item]> for SmallVec { - #[inline] - fn borrow(&self) -> &[A::Item] { - self - } -} - -impl BorrowMut<[A::Item]> for SmallVec { - #[inline] - fn borrow_mut(&mut self) -> &mut [A::Item] { - self - } -} - -#[cfg(feature = "std")] -impl> io::Write for SmallVec { - #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) - } - - #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) - } - - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } -} - -#[cfg(feature = "serde")] -impl Serialize for SmallVec -where - A::Item: Serialize, -{ - fn serialize(&self, serializer: S) -> Result { - let mut state = serializer.serialize_seq(Some(self.len()))?; - for item in self { - state.serialize_element(&item)?; - } - state.end() - } -} - -#[cfg(feature = "serde")] -impl<'de, A: Array> Deserialize<'de> for SmallVec -where - A::Item: Deserialize<'de>, -{ - fn deserialize>(deserializer: D) -> Result { - deserializer.deserialize_seq(SmallVecVisitor { - phantom: PhantomData, - }) - } -} - -#[cfg(feature = "serde")] -struct SmallVecVisitor { - phantom: PhantomData, -} - -#[cfg(feature = "serde")] -impl<'de, A: Array> Visitor<'de> for SmallVecVisitor -where - A::Item: Deserialize<'de>, -{ - type Value = SmallVec; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("a sequence") - } - - fn visit_seq(self, mut seq: B) -> Result - where - B: SeqAccess<'de>, - { - let len = seq.size_hint().unwrap_or(0); - let mut values = SmallVec::with_capacity(len); - - while let Some(value) = seq.next_element()? { - values.push(value); - } - - Ok(values) - } -} - -#[cfg(feature = "specialization")] -trait SpecFrom { - fn spec_from(slice: S) -> SmallVec; -} - -#[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec -where - A::Item: Clone, -{ - #[inline] - default fn spec_from(slice: &'a [A::Item]) -> SmallVec { - slice.into_iter().cloned().collect() - } -} - -#[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec -where - A::Item: Copy, -{ - #[inline] - fn spec_from(slice: &'a [A::Item]) -> SmallVec { - SmallVec::from_slice(slice) - } -} - -impl<'a, A: Array> From<&'a [A::Item]> for SmallVec -where - A::Item: Clone, -{ - #[cfg(not(feature = "specialization"))] - #[inline] - fn from(slice: &'a [A::Item]) -> SmallVec { - slice.into_iter().cloned().collect() - } - - #[cfg(feature = "specialization")] - #[inline] - fn from(slice: &'a [A::Item]) -> SmallVec { - SmallVec::spec_from(slice) - } -} - -impl From> for SmallVec { - #[inline] - fn from(vec: Vec) -> SmallVec { - SmallVec::from_vec(vec) - } -} - -impl From for SmallVec { - #[inline] - fn from(array: A) -> SmallVec { - SmallVec::from_buf(array) - } -} - -macro_rules! impl_index { - ($index_type: ty, $output_type: ty) => { - impl ops::Index<$index_type> for SmallVec { - type Output = $output_type; - #[inline] - fn index(&self, index: $index_type) -> &$output_type { - &(&**self)[index] - } - } - - impl ops::IndexMut<$index_type> for SmallVec { - #[inline] - fn index_mut(&mut self, index: $index_type) -> &mut $output_type { - &mut (&mut **self)[index] - } - } - }; -} - -impl_index!(usize, A::Item); -impl_index!(ops::Range, [A::Item]); -impl_index!(ops::RangeFrom, [A::Item]); -impl_index!(ops::RangeTo, [A::Item]); -impl_index!(ops::RangeFull, [A::Item]); - -impl ExtendFromSlice for SmallVec -where - A::Item: Copy, -{ - fn extend_from_slice(&mut self, other: &[A::Item]) { - SmallVec::extend_from_slice(self, other) - } -} - -impl FromIterator for SmallVec { - fn from_iter>(iterable: I) -> SmallVec { - let mut v = SmallVec::new(); - v.extend(iterable); - v - } -} - -impl Extend for SmallVec { - fn extend>(&mut self, iterable: I) { - let mut iter = iterable.into_iter(); - let (lower_size_bound, _) = iter.size_hint(); - self.reserve(lower_size_bound); - - unsafe { - let (ptr, len_ptr, cap) = self.triple_mut(); - let mut len = SetLenOnDrop::new(len_ptr); - while len.get() < cap { - if let Some(out) = iter.next() { - ptr::write(ptr.offset(len.get() as isize), out); - len.increment_len(1); - } else { - return; - } - } - } - - for elem in iter { - self.push(elem); - } - } -} - -impl fmt::Debug for SmallVec -where - A::Item: fmt::Debug, -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl Default for SmallVec { - #[inline] - fn default() -> SmallVec { - SmallVec::new() - } -} - -#[cfg(feature = "may_dangle")] -unsafe impl<#[may_dangle] A: Array> Drop for SmallVec { - fn drop(&mut self) { - unsafe { - if self.spilled() { - let (ptr, len) = self.data.heap(); - Vec::from_raw_parts(ptr, len, self.capacity); - } else { - ptr::drop_in_place(&mut self[..]); - } - } - } -} - -#[cfg(not(feature = "may_dangle"))] -impl Drop for SmallVec { - fn drop(&mut self) { - unsafe { - if self.spilled() { - let (ptr, len) = self.data.heap(); - Vec::from_raw_parts(ptr, len, self.capacity); - } else { - ptr::drop_in_place(&mut self[..]); - } - } - } -} - -impl Clone for SmallVec -where - A::Item: Clone, -{ - fn clone(&self) -> SmallVec { - let mut new_vector = SmallVec::with_capacity(self.len()); - for element in self.iter() { - new_vector.push((*element).clone()) - } - new_vector - } -} - -impl PartialEq> for SmallVec -where - A::Item: PartialEq, -{ - #[inline] - fn eq(&self, other: &SmallVec) -> bool { - self[..] == other[..] - } - #[inline] - fn ne(&self, other: &SmallVec) -> bool { - self[..] != other[..] - } -} - -impl Eq for SmallVec where A::Item: Eq {} - -impl PartialOrd for SmallVec -where - A::Item: PartialOrd, -{ - #[inline] - fn partial_cmp(&self, other: &SmallVec) -> Option { - PartialOrd::partial_cmp(&**self, &**other) - } -} - -impl Ord for SmallVec -where - A::Item: Ord, -{ - #[inline] - fn cmp(&self, other: &SmallVec) -> cmp::Ordering { - Ord::cmp(&**self, &**other) - } -} - -impl Hash for SmallVec -where - A::Item: Hash, -{ - fn hash(&self, state: &mut H) { - (**self).hash(state) - } -} - -unsafe impl Send for SmallVec where A::Item: Send {} - -/// An iterator that consumes a `SmallVec` and yields its items by value. -/// -/// Returned from [`SmallVec::into_iter`][1]. -/// -/// [1]: struct.SmallVec.html#method.into_iter -pub struct IntoIter { - data: SmallVec, - current: usize, - end: usize, -} - -impl Drop for IntoIter { - fn drop(&mut self) { - for _ in self {} - } -} - -impl Iterator for IntoIter { - type Item = A::Item; - - #[inline] - fn next(&mut self) -> Option { - if self.current == self.end { - None - } else { - unsafe { - let current = self.current as isize; - self.current += 1; - Some(ptr::read(self.data.as_ptr().offset(current))) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let size = self.end - self.current; - (size, Some(size)) - } -} - -impl DoubleEndedIterator for IntoIter { - #[inline] - fn next_back(&mut self) -> Option { - if self.current == self.end { - None - } else { - unsafe { - self.end -= 1; - Some(ptr::read(self.data.as_ptr().offset(self.end as isize))) - } - } - } -} - -impl ExactSizeIterator for IntoIter {} - -impl IntoIterator for SmallVec { - type IntoIter = IntoIter; - type Item = A::Item; - fn into_iter(mut self) -> Self::IntoIter { - unsafe { - // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements - let len = self.len(); - self.set_len(0); - IntoIter { - data: self, - current: 0, - end: len, - } - } - } -} - -impl<'a, A: Array> IntoIterator for &'a SmallVec { - type IntoIter = slice::Iter<'a, A::Item>; - type Item = &'a A::Item; - fn into_iter(self) -> Self::IntoIter { - self.iter() - } -} - -impl<'a, A: Array> IntoIterator for &'a mut SmallVec { - type IntoIter = slice::IterMut<'a, A::Item>; - type Item = &'a mut A::Item; - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() - } -} - -/// Types that can be used as the backing store for a SmallVec -pub unsafe trait Array { - /// The type of the array's elements. - type Item; - /// Returns a mutable pointer to the first element of the array. - fn as_mut_ptr(&mut self) -> *mut Self::Item; - /// Returns a pointer to the first element of the array. - fn as_ptr(&self) -> *const Self::Item; - /// Returns the number of items the array can hold. - fn size() -> usize; -} - -/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. -/// -/// Copied from https://github.com/rust-lang/rust/pull/36355 -struct SetLenOnDrop<'a> { - len: &'a mut usize, - local_len: usize, -} - -impl<'a> SetLenOnDrop<'a> { - #[inline] - fn new(len: &'a mut usize) -> Self { - SetLenOnDrop { - local_len: *len, - len: len, - } - } - - #[inline] - fn get(&self) -> usize { - self.local_len - } - - #[inline] - fn increment_len(&mut self, increment: usize) { - self.local_len += increment; - } -} - -impl<'a> Drop for SetLenOnDrop<'a> { - #[inline] - fn drop(&mut self) { - *self.len = self.local_len; - } -} - -macro_rules! impl_array( - ($($size:expr),+) => { - $( - unsafe impl Array for [T; $size] { - type Item = T; - fn as_mut_ptr(&mut self) -> *mut T { self.as_mut().as_mut_ptr() } - fn as_ptr(&self) -> *const T { self.as_ref().as_ptr() } - fn size() -> usize { $size } - } - )+ - } -); - -impl_array!( - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100, - 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, - 0x100000 -); - -#[cfg(test)] -mod tests { - extern crate alloc; - - use crate::SmallVec; - use alloc::{boxed::Box, rc::Rc}; - use core::iter::FromIterator; - - #[test] - pub fn test_zero() { - let mut v = SmallVec::<[_; 0]>::new(); - assert!(!v.spilled()); - v.push(0usize); - assert!(v.spilled()); - assert_eq!(&*v, &[0]); - } - - // We heap allocate all these strings so that double frees will show up under valgrind. - - #[test] - pub fn test_inline() { - let mut v = SmallVec::<[_; 16]>::new(); - v.push("hello"); - v.push("there"); - assert_eq!(&*v, &["hello", "there",][..]); - } - - #[test] - pub fn test_spill() { - let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello"); - assert_eq!(v[0], "hello"); - v.push("there"); - v.push("burma"); - assert_eq!(v[0], "hello"); - v.push("shave"); - assert_eq!(&*v, &["hello", "there", "burma", "shave",][..]); - } - - #[test] - pub fn test_double_spill() { - let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello"); - v.push("there"); - v.push("burma"); - v.push("shave"); - v.push("hello"); - v.push("there"); - v.push("burma"); - v.push("shave"); - assert_eq!( - &*v, - &["hello", "there", "burma", "shave", "hello", "there", "burma", "shave",][..] - ); - } - - /// https://github.com/servo/rust-smallvec/issues/4 - #[test] - fn issue_4() { - SmallVec::<[Box; 2]>::new(); - } - - /// https://github.com/servo/rust-smallvec/issues/5 - #[test] - fn issue_5() { - assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some()); - } - - #[test] - fn test_with_capacity() { - let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(1); - assert!(v.is_empty()); - assert!(!v.spilled()); - assert_eq!(v.capacity(), 3); - - let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(10); - assert!(v.is_empty()); - assert!(v.spilled()); - assert_eq!(v.capacity(), 10); - } - - #[test] - fn drain() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - assert_eq!(v.drain().collect::>(), &[3]); - - // spilling the vec - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v.drain().collect::>(), &[3, 4, 5]); - } - - #[test] - fn drain_rev() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - assert_eq!(v.drain().rev().collect::>(), &[3]); - - // spilling the vec - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v.drain().rev().collect::>(), &[5, 4, 3]); - } - - #[test] - fn into_iter() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - assert_eq!(v.into_iter().collect::>(), &[3]); - - // spilling the vec - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); - } - - #[test] - fn into_iter_rev() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - assert_eq!(v.into_iter().rev().collect::>(), &[3]); - - // spilling the vec - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); - } - - #[test] - fn into_iter_drop() { - use core::cell::Cell; - - struct DropCounter<'a>(&'a Cell); - - impl<'a> Drop for DropCounter<'a> { - fn drop(&mut self) { - self.0.set(self.0.get() + 1); - } - } - - { - let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); - v.push(DropCounter(&cell)); - v.into_iter(); - assert_eq!(cell.get(), 1); - } - - { - let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); - v.push(DropCounter(&cell)); - v.push(DropCounter(&cell)); - assert!(v.into_iter().next().is_some()); - assert_eq!(cell.get(), 2); - } - - { - let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); - v.push(DropCounter(&cell)); - v.push(DropCounter(&cell)); - v.push(DropCounter(&cell)); - assert!(v.into_iter().next().is_some()); - assert_eq!(cell.get(), 3); - } - { - let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); - v.push(DropCounter(&cell)); - v.push(DropCounter(&cell)); - v.push(DropCounter(&cell)); - { - let mut it = v.into_iter(); - assert!(it.next().is_some()); - assert!(it.next_back().is_some()); - } - assert_eq!(cell.get(), 3); - } - } - - #[test] - fn test_capacity() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.reserve(1); - assert_eq!(v.capacity(), 2); - assert!(!v.spilled()); - - v.reserve_exact(0x100); - assert!(v.capacity() >= 0x100); - - v.push(0); - v.push(1); - v.push(2); - v.push(3); - - v.shrink_to_fit(); - assert!(v.capacity() < 0x100); - } - - #[test] - fn test_truncate() { - let mut v: SmallVec<[Box; 8]> = SmallVec::new(); - - for x in 0..8 { - v.push(Box::new(x)); - } - v.truncate(4); - - assert_eq!(v.len(), 4); - assert!(!v.spilled()); - - assert_eq!(*v.swap_remove(1), 1); - assert_eq!(*v.remove(1), 3); - v.insert(1, Box::new(3)); - - assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); - } - - #[test] - fn test_insert_many() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - for x in 0..4 { - v.push(x); - } - assert_eq!(v.len(), 4); - v.insert_many(1, [5, 6].iter().cloned()); - assert_eq!( - &v.iter().map(|v| *v).collect::>(), - &[0, 5, 6, 1, 2, 3] - ); - } - - struct MockHintIter { - x: T, - hint: usize, - } - impl Iterator for MockHintIter { - type Item = T::Item; - fn next(&mut self) -> Option { - self.x.next() - } - fn size_hint(&self) -> (usize, Option) { - (self.hint, None) - } - } - - #[test] - fn test_insert_many_short_hint() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - for x in 0..4 { - v.push(x); - } - assert_eq!(v.len(), 4); - v.insert_many( - 1, - MockHintIter { - x: [5, 6].iter().cloned(), - hint: 5, - }, - ); - assert_eq!( - &v.iter().map(|v| *v).collect::>(), - &[0, 5, 6, 1, 2, 3] - ); - } - - #[test] - fn test_insert_many_long_hint() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - for x in 0..4 { - v.push(x); - } - assert_eq!(v.len(), 4); - v.insert_many( - 1, - MockHintIter { - x: [5, 6].iter().cloned(), - hint: 1, - }, - ); - assert_eq!( - &v.iter().map(|v| *v).collect::>(), - &[0, 5, 6, 1, 2, 3] - ); - } - - #[cfg(feature = "std")] - #[test] - // https://github.com/servo/rust-smallvec/issues/96 - fn test_insert_many_panic() { - struct PanicOnDoubleDrop { - dropped: Box, - } - - impl Drop for PanicOnDoubleDrop { - fn drop(&mut self) { - assert!(!*self.dropped, "already dropped"); - *self.dropped = true; - } - } - - struct BadIter; - impl Iterator for BadIter { - type Item = PanicOnDoubleDrop; - fn size_hint(&self) -> (usize, Option) { - (1, None) - } - fn next(&mut self) -> Option { - panic!() - } - } - - let mut vec: SmallVec<[PanicOnDoubleDrop; 0]> = vec![ - PanicOnDoubleDrop { - dropped: Box::new(false), - }, - PanicOnDoubleDrop { - dropped: Box::new(false), - }, - ] - .into(); - let result = ::std::panic::catch_unwind(move || { - vec.insert_many(0, BadIter); - }); - assert!(result.is_err()); - } - - #[test] - #[should_panic] - fn test_invalid_grow() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - v.extend(0..8); - v.grow(5); - } - - #[test] - fn test_insert_from_slice() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - for x in 0..4 { - v.push(x); - } - assert_eq!(v.len(), 4); - v.insert_from_slice(1, &[5, 6]); - assert_eq!( - &v.iter().map(|v| *v).collect::>(), - &[0, 5, 6, 1, 2, 3] - ); - } - - #[test] - fn test_extend_from_slice() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); - for x in 0..4 { - v.push(x); - } - assert_eq!(v.len(), 4); - v.extend_from_slice(&[5, 6]); - assert_eq!( - &v.iter().map(|v| *v).collect::>(), - &[0, 1, 2, 3, 5, 6] - ); - } - - #[test] - #[should_panic] - fn test_drop_panic_smallvec() { - // This test should only panic once, and not double panic, - // which would mean a double drop - struct DropPanic; - - impl Drop for DropPanic { - fn drop(&mut self) { - panic!("drop"); - } - } - - let mut v = SmallVec::<[_; 1]>::new(); - v.push(DropPanic); - } - - #[test] - fn test_eq() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - let mut b: SmallVec<[u32; 2]> = SmallVec::new(); - let mut c: SmallVec<[u32; 2]> = SmallVec::new(); - // a = [1, 2] - a.push(1); - a.push(2); - // b = [1, 2] - b.push(1); - b.push(2); - // c = [3, 4] - c.push(3); - c.push(4); - - assert!(a == b); - assert!(a != c); - } - - #[test] - fn test_ord() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - let mut b: SmallVec<[u32; 2]> = SmallVec::new(); - let mut c: SmallVec<[u32; 2]> = SmallVec::new(); - // a = [1] - a.push(1); - // b = [1, 1] - b.push(1); - b.push(1); - // c = [1, 2] - c.push(1); - c.push(2); - - assert!(a < b); - assert!(b > a); - assert!(b < c); - assert!(c > b); - } - - #[cfg(feature = "std")] - #[test] - fn test_hash() { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hash; - - { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - let b = [1, 2]; - a.extend(b.iter().cloned()); - 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 = DefaultHasher::new(); - assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); - } - } - - #[test] - fn test_as_ref() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - a.push(1); - assert_eq!(a.as_ref(), [1]); - a.push(2); - assert_eq!(a.as_ref(), [1, 2]); - a.push(3); - assert_eq!(a.as_ref(), [1, 2, 3]); - } - - #[test] - fn test_as_mut() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - a.push(1); - assert_eq!(a.as_mut(), [1]); - a.push(2); - assert_eq!(a.as_mut(), [1, 2]); - a.push(3); - assert_eq!(a.as_mut(), [1, 2, 3]); - a.as_mut()[1] = 4; - assert_eq!(a.as_mut(), [1, 4, 3]); - } - - #[test] - fn test_borrow() { - use core::borrow::Borrow; - - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - a.push(1); - assert_eq!(a.borrow(), [1]); - a.push(2); - assert_eq!(a.borrow(), [1, 2]); - a.push(3); - assert_eq!(a.borrow(), [1, 2, 3]); - } - - #[test] - fn test_borrow_mut() { - use core::borrow::BorrowMut; - - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - a.push(1); - assert_eq!(a.borrow_mut(), [1]); - a.push(2); - assert_eq!(a.borrow_mut(), [1, 2]); - a.push(3); - assert_eq!(a.borrow_mut(), [1, 2, 3]); - BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; - assert_eq!(a.borrow_mut(), [1, 4, 3]); - } - - #[test] - fn test_from() { - assert_eq!(&SmallVec::<[u32; 2]>::from(&[1][..])[..], [1]); - assert_eq!(&SmallVec::<[u32; 2]>::from(&[1, 2, 3][..])[..], [1, 2, 3]); - - let vec = vec![]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); - - let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); - - let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); - - let array = [1]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from(array); - assert_eq!(&*small_vec, &[1]); - drop(small_vec); - - let array = [99; 128]; - let small_vec: SmallVec<[u8; 128]> = SmallVec::from(array); - assert_eq!(&*small_vec, vec![99u8; 128].as_slice()); - drop(small_vec); - } - - #[test] - fn test_from_slice() { - assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1][..])[..], [1]); - assert_eq!( - &SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], - [1, 2, 3] - ); - } - - #[test] - fn test_exact_size_iterator() { - let mut vec = SmallVec::<[u32; 2]>::from(&[1, 2, 3][..]); - assert_eq!(vec.clone().into_iter().len(), 3); - assert_eq!(vec.drain().len(), 3); - } - - #[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"); - } - - #[test] - fn test_into_vec() { - let vec = SmallVec::<[u8; 2]>::from_iter(0..2); - assert_eq!(vec.into_vec(), vec![0, 1]); - - let vec = SmallVec::<[u8; 2]>::from_iter(0..3); - assert_eq!(vec.into_vec(), vec![0, 1, 2]); - } - - #[test] - fn test_into_inner() { - let vec = SmallVec::<[u8; 2]>::from_iter(0..2); - assert_eq!(vec.into_inner(), Ok([0, 1])); - - let vec = SmallVec::<[u8; 2]>::from_iter(0..1); - assert_eq!(vec.clone().into_inner(), Err(vec)); - - let vec = SmallVec::<[u8; 2]>::from_iter(0..3); - assert_eq!(vec.clone().into_inner(), Err(vec)); - } - - #[test] - fn test_from_vec() { - let vec = vec![]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); - - let vec = vec![]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); - - let vec = vec![1]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1]); - drop(small_vec); - - let vec = vec![1, 2, 3]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3]); - drop(small_vec); - - let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); - - let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); - } - - #[test] - fn test_retain() { - // Test inline data storate - let mut sv: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); - sv.retain(|&mut i| i != 3); - assert_eq!(sv.pop(), Some(4)); - assert_eq!(sv.pop(), Some(2)); - assert_eq!(sv.pop(), Some(1)); - assert_eq!(sv.pop(), None); - - // Test spilled data storage - let mut sv: SmallVec<[i32; 3]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); - sv.retain(|&mut i| i != 3); - assert_eq!(sv.pop(), Some(4)); - assert_eq!(sv.pop(), Some(2)); - assert_eq!(sv.pop(), Some(1)); - assert_eq!(sv.pop(), None); - - // Test that drop implementations are called for inline. - let one = Rc::new(1); - let mut sv: SmallVec<[Rc; 3]> = SmallVec::new(); - sv.push(Rc::clone(&one)); - assert_eq!(Rc::strong_count(&one), 2); - sv.retain(|_| false); - assert_eq!(Rc::strong_count(&one), 1); - - // Test that drop implementations are called for spilled data. - let mut sv: SmallVec<[Rc; 1]> = SmallVec::new(); - sv.push(Rc::clone(&one)); - sv.push(Rc::new(2)); - assert_eq!(Rc::strong_count(&one), 2); - sv.retain(|_| false); - assert_eq!(Rc::strong_count(&one), 1); - } - - #[test] - fn test_dedup() { - let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); - dupes.dedup(); - assert_eq!(&*dupes, &[1, 2, 3]); - - let mut empty: SmallVec<[i32; 5]> = SmallVec::new(); - empty.dedup(); - assert!(empty.is_empty()); - - let mut all_ones: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 1, 1, 1]); - all_ones.dedup(); - assert_eq!(all_ones.len(), 1); - - let mut no_dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 4, 5]); - no_dupes.dedup(); - assert_eq!(no_dupes.len(), 5); - } - - #[test] - fn test_resize() { - let mut v: SmallVec<[i32; 8]> = SmallVec::new(); - v.push(1); - v.resize(5, 0); - assert_eq!(v[..], [1, 0, 0, 0, 0][..]); - - v.resize(2, -1); - assert_eq!(v[..], [1, 0][..]); - } - - #[cfg(feature = "std")] - #[test] - fn test_write() { - use std::io::Write; - - let data = [1, 2, 3, 4, 5]; - - let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); - let len = small_vec.write(&data[..]).unwrap(); - assert_eq!(len, 5); - assert_eq!(small_vec.as_ref(), data.as_ref()); - - let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); - small_vec.write_all(&data[..]).unwrap(); - assert_eq!(small_vec.as_ref(), data.as_ref()); - } - - #[cfg(feature = "serde")] - extern crate bincode; - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - use self::bincode::{config, deserialize}; - let mut small_vec: SmallVec<[i32; 2]> = SmallVec::new(); - small_vec.push(1); - let encoded = config().limit(100).serialize(&small_vec).unwrap(); - let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); - assert_eq!(small_vec, decoded); - small_vec.push(2); - // Spill the vec - small_vec.push(3); - small_vec.push(4); - // Check again after spilling. - let encoded = config().limit(100).serialize(&small_vec).unwrap(); - let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); - assert_eq!(small_vec, decoded); - } - - #[test] - fn grow_to_shrink() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(1); - v.push(2); - v.push(3); - assert!(v.spilled()); - v.clear(); - // Shrink to inline. - v.grow(2); - assert!(!v.spilled()); - assert_eq!(v.capacity(), 2); - assert_eq!(v.len(), 0); - v.push(4); - assert_eq!(v[..], [4]); - } - - #[test] - fn resumable_extend() { - let s = "a b c"; - // This iterator yields: (Some('a'), None, Some('b'), None, Some('c')), None - let it = s - .chars() - .scan(0, |_, ch| if ch.is_whitespace() { None } else { Some(ch) }); - let mut v: SmallVec<[char; 4]> = SmallVec::new(); - v.extend(it); - assert_eq!(v[..], ['a']); - } - - #[test] - fn grow_spilled_same_size() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); - v.push(0); - v.push(1); - v.push(2); - assert!(v.spilled()); - assert_eq!(v.capacity(), 4); - // grow with the same capacity - v.grow(4); - assert_eq!(v.capacity(), 4); - assert_eq!(v[..], [0, 1, 2]); - } -} diff --git a/src/array.rs b/src/array.rs new file mode 100644 index 0000000..7f7a096 --- /dev/null +++ b/src/array.rs @@ -0,0 +1,30 @@ +/// Types that can be used as the backing store for a SmallVec +pub unsafe trait Array { + /// The type of the array's elements. + type Item; + /// Returns a mutable pointer to the first element of the array. + fn as_mut_ptr(&mut self) -> *mut Self::Item; + /// Returns a pointer to the first element of the array. + fn as_ptr(&self) -> *const Self::Item; + /// Returns the number of items the array can hold. + fn size() -> usize; +} + +macro_rules! impl_array( + ($($size:expr),+) => { + $( + unsafe impl Array for [T; $size] { + type Item = T; + fn as_mut_ptr(&mut self) -> *mut T { self.as_mut().as_mut_ptr() } + fn as_ptr(&self) -> *const T { self.as_ref().as_ptr() } + fn size() -> usize { $size } + } + )+ + } +); + +impl_array!( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100, + 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, + 0x100000 +); diff --git a/src/drain.rs b/src/drain.rs new file mode 100644 index 0000000..e7adb26 --- /dev/null +++ b/src/drain.rs @@ -0,0 +1,44 @@ +use core::{ptr, slice}; + +/// An iterator that removes the items from a `SmallVec` and yields them by value. +/// +/// Returned from [`SmallVec::drain`][1]. +/// +/// [1]: struct.SmallVec.html#method.drain +pub struct Drain<'a, T: 'a> { + pub(crate) iter: slice::IterMut<'a, T>, +} + +impl<'a, T: 'a> Iterator for Drain<'a, T> { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + self.iter + .next() + .map(|reference| unsafe { ptr::read(reference) }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a, T: 'a> DoubleEndedIterator for Drain<'a, T> { + #[inline] + fn next_back(&mut self) -> Option { + self.iter + .next_back() + .map(|reference| unsafe { ptr::read(reference) }) + } +} + +impl<'a, T> ExactSizeIterator for Drain<'a, T> {} + +impl<'a, T: 'a> Drop for Drain<'a, T> { + fn drop(&mut self) { + // Destroy the remaining elements. + for _ in self.by_ref() {} + } +} diff --git a/src/extend_from_slice.rs b/src/extend_from_slice.rs new file mode 100644 index 0000000..ad6a975 --- /dev/null +++ b/src/extend_from_slice.rs @@ -0,0 +1,29 @@ +/// Trait to be implemented by a collection that can be extended from a slice +/// +/// ## Example +/// +/// ```rust +/// use smallvec::{ExtendFromSlice, SmallVec}; +/// +/// fn initialize>(v: &mut V) { +/// v.extend_from_slice(b"Test!"); +/// } +/// +/// let mut vec = Vec::new(); +/// initialize(&mut vec); +/// assert_eq!(&vec, b"Test!"); +/// +/// let mut small_vec = SmallVec::<[u8; 8]>::new(); +/// initialize(&mut small_vec); +/// assert_eq!(&small_vec as &[_], b"Test!"); +/// ``` +pub trait ExtendFromSlice { + /// Extends a collection from a slice of its element type + fn extend_from_slice(&mut self, other: &[T]); +} + +impl ExtendFromSlice for Vec { + fn extend_from_slice(&mut self, other: &[T]) { + Vec::extend_from_slice(self, other) + } +} diff --git a/src/into_iter.rs b/src/into_iter.rs new file mode 100644 index 0000000..1a62b64 --- /dev/null +++ b/src/into_iter.rs @@ -0,0 +1,60 @@ +#[cfg(not(feature = "const_generics"))] +use crate::Array; +use crate::SmallVec; +use core::ptr; + +/// An iterator that consumes a `SmallVec` and yields its items by value. +/// +/// Returned from [`SmallVec::into_iter`][1]. +/// +/// [1]: struct.SmallVec.html#method.into_iter +pub struct IntoIter { + pub(crate) data: SmallVec, + pub(crate) current: usize, + pub(crate) end: usize, +} + +impl Drop for IntoIter { + fn drop(&mut self) { + for _ in self {} + } +} + +impl Iterator for IntoIter { + type Item = A::Item; + + #[inline] + fn next(&mut self) -> Option { + if self.current == self.end { + None + } else { + unsafe { + let current = self.current as isize; + self.current += 1; + Some(ptr::read(self.data.as_ptr().offset(current))) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let size = self.end - self.current; + (size, Some(size)) + } +} + +impl DoubleEndedIterator for IntoIter { + #[inline] + fn next_back(&mut self) -> Option { + if self.current == self.end { + None + } else { + unsafe { + self.end -= 1; + Some(ptr::read(self.data.as_ptr().offset(self.end as isize))) + } + } + } +} + +impl ExactSizeIterator for IntoIter {} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..876a2e7 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,59 @@ +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! 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. +//! +//! ## no_std support +//! +//! By default, `smallvec` depends on `libstd`. However, it can be configured to use the unstable +//! `liballoc` API instead, for use on platforms that have `liballoc` but not `libstd`. This +//! configuration is currently unstable and is not guaranteed to work on all versions of Rust. +//! +//! To depend on `smallvec` without `libstd`, use `default-features = false` in the `smallvec` +//! section of Cargo.toml to disable its `"alloc"` feature. +//! +//! ## `union` feature +//! +//! When the `union` feature is enabled `smallvec` will track its state (inline or spilled) +//! without the use of an enum tag, reducing the size of the `smallvec` by one machine word. +//! This means that there is potentially no space overhead compared to `Vec`. +//! Note that `smallvec` can still be larger than `Vec` if the inline buffer is larger than two +//! machine words. +//! +//! To use this feature add `features = ["union"]` in the `smallvec` section of Cargo.toml. +//! Note that this feature requires a nightly compiler (for now). + +#![cfg_attr(feature = "const_generics", feature(const_generics))] +#![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] +#![cfg_attr(feature = "specialization", feature(specialization))] +#![cfg_attr(feature = "union", feature(untagged_unions))] +#![deny(missing_docs)] + +#[cfg(not(feature = "const_generics"))] +mod array; +mod drain; +mod extend_from_slice; +mod into_iter; +#[macro_use] +mod macros; +mod set_len_on_drop; +mod small_vec; +mod small_vec_data; +#[cfg(feature = "serde")] +mod small_vec_visitor; +#[cfg(feature = "specialization")] +mod spec_from; +#[cfg(test)] +mod tests; +mod utils; + +#[cfg(not(feature = "const_generics"))] +pub use self::array::Array; +pub use self::{ + drain::Drain, extend_from_slice::ExtendFromSlice, into_iter::IntoIter, small_vec::SmallVec, +}; diff --git a/src/macros.rs b/src/macros.rs new file mode 100644 index 0000000..f84f868 --- /dev/null +++ b/src/macros.rs @@ -0,0 +1,71 @@ +/// `panic!()` in debug builds, optimization hint in release. +#[cfg(not(feature = "union"))] +macro_rules! debug_unreachable { + () => { + debug_unreachable!("entered unreachable code") + }; + ($e:expr) => { + if cfg!(not(debug_assertions)) { + crate::utils::unreachable(); + } else { + panic!($e); + } + }; +} + +/// Creates a [`SmallVec`] containing the arguments. +/// +/// `smallvec!` allows `SmallVec`s to be defined with the same syntax as array expressions. +/// There are two forms of this macro: +/// +/// - Create a [`SmallVec`] containing a given list of elements: +/// +/// ``` +/// # #[macro_use] extern crate smallvec; +/// # use smallvec::SmallVec; +/// # fn main() { +/// let v: SmallVec<[_; 128]> = smallvec![1, 2, 3]; +/// assert_eq!(v[0], 1); +/// assert_eq!(v[1], 2); +/// assert_eq!(v[2], 3); +/// # } +/// ``` +/// +/// - Create a [`SmallVec`] from a given element and size: +/// +/// ``` +/// # #[macro_use] extern crate smallvec; +/// # use smallvec::SmallVec; +/// # fn main() { +/// let v: SmallVec<[_; 0x8000]> = smallvec![1; 3]; +/// assert_eq!(v, SmallVec::from_buf([1, 1, 1])); +/// # } +/// ``` +/// +/// Note that unlike array expressions this syntax supports all elements +/// which implement [`Clone`] and the number of elements doesn't have to be +/// a constant. +/// +/// This will use `clone` to duplicate an expression, so one should be careful +/// using this with types having a nonstandard `Clone` implementation. For +/// example, `smallvec![Rc::new(1); 5]` will create a vector of five references +/// to the same boxed integer value, not five references pointing to independently +/// boxed integers. +#[macro_export] +macro_rules! smallvec { + // count helper: transform any expression into 1 + (@one $x:expr) => (1usize); + ($elem:expr; $n:expr) => ({ + $crate::SmallVec::from_elem($elem, $n) + }); + ($($x:expr),*$(,)*) => ({ + let count = 0usize $(+ smallvec!(@one $x))*; + let mut vec = $crate::SmallVec::new(); + if count <= vec.inline_size() { + $(vec.push($x);)* + vec + } else { + $crate::SmallVec::from_vec(vec![$($x,)*]) + } + }); +} diff --git a/src/set_len_on_drop.rs b/src/set_len_on_drop.rs new file mode 100644 index 0000000..55c3ff0 --- /dev/null +++ b/src/set_len_on_drop.rs @@ -0,0 +1,34 @@ +/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope. +/// +/// Copied from https://github.com/rust-lang/rust/pull/36355 +pub struct SetLenOnDrop<'a> { + len: &'a mut usize, + local_len: usize, +} + +impl<'a> SetLenOnDrop<'a> { + #[inline] + pub fn new(len: &'a mut usize) -> Self { + SetLenOnDrop { + local_len: *len, + len: len, + } + } + + #[inline] + pub fn get(&self) -> usize { + self.local_len + } + + #[inline] + pub fn increment_len(&mut self, increment: usize) { + self.local_len += increment; + } +} + +impl<'a> Drop for SetLenOnDrop<'a> { + #[inline] + fn drop(&mut self) { + *self.len = self.local_len; + } +} diff --git a/src/small_vec.rs b/src/small_vec.rs new file mode 100644 index 0000000..46f3acc --- /dev/null +++ b/src/small_vec.rs @@ -0,0 +1,1160 @@ +#[cfg(feature = "serde")] +use crate::small_vec_visitor::SmallVecVisitor; +#[cfg(feature = "specialization")] +use crate::spec_from::SpecFrom; +use crate::utils::{deallocate, unreachable}; +#[cfg(not(feature = "const_generics"))] +use crate::Array; +use crate::{ + set_len_on_drop::SetLenOnDrop, small_vec_data::SmallVecData, Drain, ExtendFromSlice, IntoIter, +}; +use core::{ + borrow::{Borrow, BorrowMut}, + cmp::{Eq, Ord, Ordering, PartialOrd}, + fmt::{self, Debug}, + hash::{Hash, Hasher}, + iter::{repeat, FromIterator}, + mem::{self, MaybeUninit}, + ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}, + ptr, slice, +}; +#[cfg(feature = "serde")] +use serde::{ + de::{Deserialize, Deserializer}, + ser::{Serialize, SerializeSeq, Serializer}, +}; +#[cfg(feature = "std")] +use std::io; +#[cfg(feature = "serde")] +use std::marker::PhantomData; + +/// 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. +/// +/// ## Example +/// +/// ```rust +/// use smallvec::SmallVec; +/// let mut v = SmallVec::<[u8; 4]>::new(); // initialize an empty vector +/// +/// // The vector 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 { + // The capacity field is used to determine which of the storage variants is active: + // If capacity <= A::size() then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use). + // If capacity > A::size() then the heap variant is used and capacity holds the size of the memory allocation. + capacity: usize, + data: SmallVecData, +} + +impl SmallVec { + /// Construct an empty vector + #[inline] + pub fn new() -> SmallVec { + unsafe { + SmallVec { + capacity: 0, + data: SmallVecData::from_inline(mem::uninitialized()), + } + } + } + + /// Construct an empty vector with enough capacity pre-allocated to store at least `n` + /// elements. + /// + /// Will create a heap allocation only if `n` is larger than the inline capacity. + /// + /// ``` + /// # use smallvec::SmallVec; + /// + /// let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(100); + /// + /// assert!(v.is_empty()); + /// assert!(v.capacity() >= 100); + /// ``` + #[inline] + pub fn with_capacity(n: usize) -> Self { + let mut v = SmallVec::new(); + v.reserve_exact(n); + v + } + + /// Construct a new `SmallVec` from a `Vec`. + /// + /// Elements will be copied to the inline buffer if vec.capacity() <= A::size(). + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let vec = vec![1, 2, 3, 4, 5]; + /// let small_vec: SmallVec<[_; 3]> = SmallVec::from_vec(vec); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_vec(mut vec: Vec) -> SmallVec { + if vec.capacity() <= A::size() { + unsafe { + let mut data = SmallVecData::::from_inline(mem::uninitialized()); + let len = vec.len(); + vec.set_len(0); + ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().as_mut_ptr(), len); + + SmallVec { + capacity: len, + data, + } + } + } else { + let (ptr, cap, len) = (vec.as_mut_ptr(), vec.capacity(), vec.len()); + mem::forget(vec); + + SmallVec { + capacity: cap, + data: SmallVecData::from_heap(ptr, len), + } + } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5]; + /// let small_vec: SmallVec<_> = SmallVec::from_buf(buf); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_buf(buf: A) -> SmallVec { + SmallVec { + capacity: A::size(), + data: SmallVecData::from_inline(MaybeUninit::new(buf)), + } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. Also sets the length, which must be less or + /// equal to the size of `buf`. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; + /// let small_vec: SmallVec<_> = SmallVec::from_buf_and_len(buf, 5); + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec { + assert!(len <= A::size()); + unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) } + } + + /// Constructs a new `SmallVec` on the stack from an `A` without + /// copying elements. Also sets the length. The user is responsible + /// for ensuring that `len <= A::size()`. + /// + /// ```rust + /// use smallvec::SmallVec; + /// + /// let buf = [1, 2, 3, 4, 5, 0, 0, 0]; + /// let small_vec: SmallVec<_> = unsafe { + /// SmallVec::from_buf_and_len_unchecked(buf, 5) + /// }; + /// + /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + /// ``` + #[inline] + pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec { + SmallVec { + capacity: len, + data: SmallVecData::from_inline(MaybeUninit::new(buf)), + } + } + + /// 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) { + let (_, len_ptr, _) = self.triple_mut(); + *len_ptr = 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.triple().1 + } + + /// 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 { + self.triple().2 + } + + /// Returns a tuple with (data ptr, len, capacity) + /// Useful to get all SmallVec properties with a single check of the current storage variant. + #[inline] + fn triple(&self) -> (*const A::Item, usize, usize) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + (ptr, len, self.capacity) + } else { + (self.data.inline().as_ptr(), self.capacity, A::size()) + } + } + } + + /// Returns a tuple with (data ptr, len ptr, capacity) + #[inline] + fn triple_mut(&mut self) -> (*mut A::Item, &mut usize, usize) { + unsafe { + if self.spilled() { + let (ptr, len_ptr) = self.data.heap_mut(); + (ptr, len_ptr, self.capacity) + } else { + ( + self.data.inline_mut().as_mut_ptr(), + &mut self.capacity, + A::size(), + ) + } + } + } + + /// Returns `true` if the data has spilled into a separate heap-allocated buffer. + #[inline] + pub fn spilled(&self) -> bool { + self.capacity > A::size() + } + + /// Empty the vector and return an iterator over its former contents. + pub fn drain(&mut self) -> Drain { + unsafe { + let ptr = self.as_mut_ptr(); + + let current_len = self.len(); + self.set_len(0); + + let slice = slice::from_raw_parts_mut(ptr, current_len); + + Drain { + iter: slice.iter_mut(), + } + } + } + + /// Append an item to the vector. + #[inline] + pub fn push(&mut self, value: A::Item) { + unsafe { + let (_, &mut len, cap) = self.triple_mut(); + if len == cap { + self.reserve(1); + } + let (ptr, len_ptr, _) = self.triple_mut(); + *len_ptr = len + 1; + ptr::write(ptr.offset(len as isize), value); + } + } + + /// Remove an item from the end of the vector and return it, or None if empty. + #[inline] + pub fn pop(&mut self) -> Option { + unsafe { + let (ptr, len_ptr, _) = self.triple_mut(); + if *len_ptr == 0 { + return None; + } + let last_index = *len_ptr - 1; + *len_ptr = last_index; + Some(ptr::read(ptr.offset(last_index as isize))) + } + } + + /// Re-allocate to set the capacity to `max(new_cap, inline_size())`. + /// + /// Panics if `new_cap` is less than the vector's length. + pub fn grow(&mut self, new_cap: usize) { + unsafe { + let (ptr, &mut len, cap) = self.triple_mut(); + let unspilled = !self.spilled(); + assert!(new_cap >= len); + if new_cap <= self.inline_size() { + if unspilled { + return; + } + self.data = SmallVecData::from_inline(mem::uninitialized()); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); + self.capacity = len; + } else if new_cap != cap { + let mut vec = Vec::with_capacity(new_cap); + let new_alloc = vec.as_mut_ptr(); + mem::forget(vec); + ptr::copy_nonoverlapping(ptr, new_alloc, len); + self.data = SmallVecData::from_heap(new_alloc, len); + self.capacity = new_cap; + if unspilled { + return; + } + } else { + return; + } + deallocate(ptr, cap); + } + } + + /// 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.) + #[inline] + pub fn reserve(&mut self, additional: usize) { + // prefer triple_mut() even if triple() would work + // so that the optimizer removes duplicated calls to it + // from callers like insert() + let (_, &mut len, cap) = self.triple_mut(); + if cap - len < additional { + let new_cap = len + .checked_add(additional) + .and_then(usize::checked_next_power_of_two) + .unwrap_or(usize::max_value()); + self.grow(new_cap); + } + } + + /// Reserve the minimum capacity for `additional` more elements to be inserted. + /// + /// Panics if the new capacity overflows `usize`. + pub fn reserve_exact(&mut self, additional: usize) { + let (_, &mut len, cap) = self.triple_mut(); + if cap - len < additional { + match len.checked_add(additional) { + Some(cap) => self.grow(cap), + None => panic!("reserve_exact overflow"), + } + } + } + + /// 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) { + if !self.spilled() { + return; + } + let len = self.len(); + if self.inline_size() >= len { + unsafe { + let (ptr, len) = self.data.heap(); + self.data = SmallVecData::from_inline(mem::uninitialized()); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); + deallocate(ptr, self.capacity); + self.capacity = len; + } + } 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) { + unsafe { + let (ptr, len_ptr, _) = self.triple_mut(); + while len < *len_ptr { + let last_index = *len_ptr - 1; + *len_ptr = last_index; + ptr::drop_in_place(ptr.offset(last_index as isize)); + } + } + } + + /// Extracts a slice containing the entire vector. + /// + /// Equivalent to `&s[..]`. + pub fn as_slice(&self) -> &[A::Item] { + self + } + + /// Extracts a mutable slice of the entire vector. + /// + /// Equivalent to `&mut s[..]`. + pub fn as_mut_slice(&mut self) -> &mut [A::Item] { + self + } + + /// 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_or_else(|| unsafe { unreachable() }) + } + + /// 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 { + unsafe { + let (mut ptr, len_ptr, _) = self.triple_mut(); + let len = *len_ptr; + assert!(index < len); + *len_ptr = len - 1; + ptr = ptr.offset(index as isize); + let item = ptr::read(ptr); + ptr::copy(ptr.offset(1), ptr, len - index - 1); + item + } + } + + /// 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); + + unsafe { + let (mut ptr, len_ptr, _) = self.triple_mut(); + let len = *len_ptr; + assert!(index <= len); + *len_ptr = len + 1; + ptr = ptr.offset(index as isize); + ptr::copy(ptr, ptr.offset(1), len - index); + ptr::write(ptr, element); + } + } + + /// Insert multiple elements at position `index`, shifting all following elements toward the + /// back. + pub fn insert_many>(&mut self, index: usize, iterable: I) { + let iter = iterable.into_iter(); + if index == self.len() { + return self.extend(iter); + } + + let (lower_size_bound, _) = iter.size_hint(); + assert!(lower_size_bound <= core::isize::MAX as usize); // Ensure offset is indexable + assert!(index + lower_size_bound >= index); // Protect against overflow + self.reserve(lower_size_bound); + + unsafe { + let old_len = self.len(); + assert!(index <= old_len); + let mut ptr = self.as_mut_ptr().offset(index as isize); + + // Move the trailing elements. + ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index); + + // In case the iterator panics, don't double-drop the items we just copied above. + self.set_len(index); + + let mut num_added = 0; + for element in iter { + let mut cur = ptr.offset(num_added as isize); + if num_added >= lower_size_bound { + // Iterator provided more elements than the hint. Move trailing items again. + self.reserve(1); + ptr = self.as_mut_ptr().offset(index as isize); + cur = ptr.offset(num_added as isize); + ptr::copy(cur, cur.offset(1), old_len - index); + } + ptr::write(cur, element); + num_added += 1; + } + if num_added < lower_size_bound { + // Iterator provided fewer elements than the hint + ptr::copy( + ptr.offset(lower_size_bound as isize), + ptr.offset(num_added as isize), + old_len - index, + ); + } + + self.set_len(old_len + num_added); + } + } + + /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto + /// the heap. + pub fn into_vec(self) -> Vec { + if self.spilled() { + unsafe { + let (ptr, len) = self.data.heap(); + let v = Vec::from_raw_parts(ptr, len, self.capacity); + mem::forget(self); + v + } + } else { + self.into_iter().collect() + } + } + + /// Convert the SmallVec into an `A` if possible. Otherwise return `Err(Self)`. + /// + /// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements), + /// or if the SmallVec is too long (and all the elements were spilled to the heap). + pub fn into_inner(self) -> Result { + if self.spilled() || self.len() != A::size() { + Err(self) + } else { + unsafe { + let data = ptr::read(&self.data); + mem::forget(self); + Ok(data.into_inline()) + } + } + } + + /// Retains only the elements specified by the predicate. + /// + /// In other words, remove all elements `e` such that `f(&e)` returns `false`. + /// This method operates in place and preserves the order of the retained + /// elements. + pub fn retain bool>(&mut self, mut f: F) { + let mut del = 0; + let len = self.len(); + for i in 0..len { + if !f(&mut self[i]) { + del += 1; + } else if del > 0 { + self.swap(i - del, i); + } + } + self.truncate(len - del); + } + + /// Removes consecutive duplicate elements. + pub fn dedup(&mut self) + where + A::Item: PartialEq, + { + self.dedup_by(|a, b| a == b); + } + + /// Removes consecutive duplicate elements using the given equality relation. + pub fn dedup_by(&mut self, mut same_bucket: F) + where + F: FnMut(&mut A::Item, &mut A::Item) -> bool, + { + // See the implementation of Vec::dedup_by in the + // standard library for an explanation of this algorithm. + let len = self.len(); + if len <= 1 { + return; + } + + let ptr = self.as_mut_ptr(); + let mut w: usize = 1; + + unsafe { + for r in 1..len { + let p_r = ptr.offset(r as isize); + let p_wm1 = ptr.offset((w - 1) as isize); + if !same_bucket(&mut *p_r, &mut *p_wm1) { + if r != w { + let p_w = p_wm1.offset(1); + mem::swap(&mut *p_r, &mut *p_w); + } + w += 1; + } + } + } + + self.truncate(w); + } + + /// Removes consecutive elements that map to the same key. + pub fn dedup_by_key(&mut self, mut key: F) + where + F: FnMut(&mut A::Item) -> K, + K: PartialEq, + { + self.dedup_by(|a, b| key(a) == key(b)); + } + + /// Creates a `SmallVec` directly from the raw components of another + /// `SmallVec`. + /// + /// # Safety + /// + /// This is highly unsafe, due to the number of invariants that aren't + /// checked: + /// + /// * `ptr` needs to have been previously allocated via `SmallVec` for its + /// spilled storage (at least, it's highly likely to be incorrect if it + /// wasn't). + /// * `ptr`'s `A::Item` type needs to be the same size and alignment that + /// it was allocated with + /// * `length` needs to be less than or equal to `capacity`. + /// * `capacity` needs to be the capacity that the pointer was allocated + /// with. + /// + /// Violating these may cause problems like corrupting the allocator's + /// internal data structures. + /// + /// Additionally, `capacity` must be greater than the amount of inline + /// storage `A` has; that is, the new `SmallVec` must need to spill over + /// into heap allocated storage. This condition is asserted against. + /// + /// The ownership of `ptr` is effectively transferred to the + /// `SmallVec` which may then deallocate, reallocate or change the + /// contents of memory pointed to by the pointer at will. Ensure + /// that nothing else uses the pointer after calling this + /// function. + /// + /// # Examples + /// + /// ``` + /// # #[macro_use] extern crate smallvec; + /// # use smallvec::SmallVec; + /// use std::mem; + /// use std::ptr; + /// + /// fn main() { + /// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3]; + /// + /// // Pull out the important parts of `v`. + /// let p = v.as_mut_ptr(); + /// let len = v.len(); + /// let cap = v.capacity(); + /// let spilled = v.spilled(); + /// + /// unsafe { + /// // Forget all about `v`. The heap allocation that stored the + /// // three values won't be deallocated. + /// mem::forget(v); + /// + /// // Overwrite memory with [4, 5, 6]. + /// // + /// // This is only safe if `spilled` is true! Otherwise, we are + /// // writing into the old `SmallVec`'s inline storage on the + /// // stack. + /// assert!(spilled); + /// for i in 0..len as isize { + /// ptr::write(p.offset(i), 4 + i); + /// } + /// + /// // Put everything back together into a SmallVec with a different + /// // amount of inline storage, but which is still less than `cap`. + /// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap); + /// assert_eq!(&*rebuilt, &[4, 5, 6]); + /// } + /// } + pub unsafe fn from_raw_parts(ptr: *mut A::Item, length: usize, capacity: usize) -> SmallVec { + assert!(capacity > A::size()); + SmallVec { + capacity, + data: SmallVecData::from_heap(ptr, length), + } + } +} + +impl SmallVec +where + A::Item: Copy, +{ + /// Copy the elements from a slice into a new `SmallVec`. + /// + /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`. + pub fn from_slice(slice: &[A::Item]) -> Self { + let len = slice.len(); + if len <= A::size() { + SmallVec { + capacity: len, + data: SmallVecData::from_inline(unsafe { + let mut data = MaybeUninit::::uninit(); + let slice_mut = &mut *data.as_mut_ptr(); + ptr::copy_nonoverlapping(slice.as_ptr(), slice_mut.as_mut_ptr(), len); + data + }), + } + } else { + let mut b = slice.to_vec(); + let (ptr, cap) = (b.as_mut_ptr(), b.capacity()); + mem::forget(b); + SmallVec { + capacity: cap, + data: SmallVecData::from_heap(ptr, len), + } + } + } + /// Copy elements from a slice into the vector at position `index`, shifting any following + /// elements toward the back. + /// + /// For slices of `Copy` types, this is more efficient than `insert`. + pub fn insert_from_slice(&mut self, index: usize, slice: &[A::Item]) { + self.reserve(slice.len()); + + let len = self.len(); + assert!(index <= len); + + unsafe { + let slice_ptr = slice.as_ptr(); + let ptr = self.as_mut_ptr().offset(index as isize); + ptr::copy(ptr, ptr.offset(slice.len() as isize), len - index); + ptr::copy_nonoverlapping(slice_ptr, ptr, slice.len()); + self.set_len(len + slice.len()); + } + } + + /// Copy elements from a slice and append them to the vector. + /// + /// For slices of `Copy` types, this is more efficient than `extend`. + #[inline] + pub fn extend_from_slice(&mut self, slice: &[A::Item]) { + let len = self.len(); + self.insert_from_slice(len, slice); + } +} + +impl SmallVec +where + A::Item: Clone, +{ + /// Resizes the vector so that its length is equal to `len`. + /// + /// If `len` is less than the current length, the vector simply truncated. + /// + /// If `len` is greater than the current length, `value` is appended to the + /// vector until its length equals `len`. + pub fn resize(&mut self, len: usize, value: A::Item) { + let old_len = self.len(); + + if len > old_len { + self.extend(repeat(value).take(len - old_len)); + } else { + self.truncate(len); + } + } + + /// Creates a `SmallVec` with `n` copies of `elem`. + /// ``` + /// use smallvec::SmallVec; + /// + /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); + /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); + /// ``` + pub fn from_elem(elem: A::Item, n: usize) -> Self { + if n > A::size() { + vec![elem; n].into() + } else { + let mut v = SmallVec::::new(); + unsafe { + let (ptr, len_ptr, _) = v.triple_mut(); + let mut local_len = SetLenOnDrop::new(len_ptr); + + for i in 0..n as isize { + core::ptr::write(ptr.offset(i), elem.clone()); + local_len.increment_len(1); + } + } + v + } + } +} + +impl Deref for SmallVec { + type Target = [A::Item]; + #[inline] + fn deref(&self) -> &[A::Item] { + unsafe { + let (ptr, len, _) = self.triple(); + slice::from_raw_parts(ptr, len) + } + } +} + +impl DerefMut for SmallVec { + #[inline] + fn deref_mut(&mut self) -> &mut [A::Item] { + unsafe { + let (ptr, &mut len, _) = self.triple_mut(); + slice::from_raw_parts_mut(ptr, len) + } + } +} + +impl AsRef<[A::Item]> for SmallVec { + #[inline] + fn as_ref(&self) -> &[A::Item] { + self + } +} + +impl AsMut<[A::Item]> for SmallVec { + #[inline] + fn as_mut(&mut self) -> &mut [A::Item] { + self + } +} + +impl Borrow<[A::Item]> for SmallVec { + #[inline] + fn borrow(&self) -> &[A::Item] { + self + } +} + +impl BorrowMut<[A::Item]> for SmallVec { + #[inline] + fn borrow_mut(&mut self) -> &mut [A::Item] { + self + } +} + +#[cfg(feature = "std")] +impl> io::Write for SmallVec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[cfg(feature = "serde")] +impl Serialize for SmallVec +where + A::Item: Serialize, +{ + fn serialize(&self, serializer: S) -> Result { + let mut state = serializer.serialize_seq(Some(self.len()))?; + for item in self { + state.serialize_element(&item)?; + } + state.end() + } +} + +#[cfg(feature = "serde")] +impl<'de, A: Array> Deserialize<'de> for SmallVec +where + A::Item: Deserialize<'de>, +{ + fn deserialize>(deserializer: D) -> Result { + deserializer.deserialize_seq(SmallVecVisitor { + phantom: PhantomData, + }) + } +} + +#[cfg(feature = "specialization")] +impl<'a, A: Array> SpecFrom for SmallVec +where + A::Item: Clone, +{ + #[inline] + default fn spec_from(slice: &'a [A::Item]) -> SmallVec { + slice.into_iter().cloned().collect() + } +} + +#[cfg(feature = "specialization")] +impl<'a, A: Array> SpecFrom for SmallVec +where + A::Item: Copy, +{ + #[inline] + fn spec_from(slice: &'a [A::Item]) -> SmallVec { + SmallVec::from_slice(slice) + } +} + +impl<'a, A: Array> From<&'a [A::Item]> for SmallVec +where + A::Item: Clone, +{ + #[cfg(not(feature = "specialization"))] + #[inline] + fn from(slice: &'a [A::Item]) -> SmallVec { + slice.into_iter().cloned().collect() + } + + #[cfg(feature = "specialization")] + #[inline] + fn from(slice: &'a [A::Item]) -> SmallVec { + SmallVec::spec_from(slice) + } +} + +impl From> for SmallVec { + #[inline] + fn from(vec: Vec) -> SmallVec { + SmallVec::from_vec(vec) + } +} + +impl From for SmallVec { + #[inline] + fn from(array: A) -> SmallVec { + SmallVec::from_buf(array) + } +} + +macro_rules! impl_index { + ($index_type: ty, $output_type: ty) => { + impl Index<$index_type> for SmallVec { + type Output = $output_type; + #[inline] + fn index(&self, index: $index_type) -> &$output_type { + &(&**self)[index] + } + } + + impl IndexMut<$index_type> for SmallVec { + #[inline] + fn index_mut(&mut self, index: $index_type) -> &mut $output_type { + &mut (&mut **self)[index] + } + } + }; +} + +impl_index!(usize, A::Item); +impl_index!(Range, [A::Item]); +impl_index!(RangeFrom, [A::Item]); +impl_index!(RangeTo, [A::Item]); +impl_index!(RangeFull, [A::Item]); + +impl ExtendFromSlice for SmallVec +where + A::Item: Copy, +{ + fn extend_from_slice(&mut self, other: &[A::Item]) { + SmallVec::extend_from_slice(self, other) + } +} + +impl FromIterator for SmallVec { + fn from_iter>(iterable: I) -> SmallVec { + let mut v = SmallVec::new(); + v.extend(iterable); + v + } +} + +impl Extend for SmallVec { + fn extend>(&mut self, iterable: I) { + let mut iter = iterable.into_iter(); + let (lower_size_bound, _) = iter.size_hint(); + self.reserve(lower_size_bound); + + unsafe { + let (ptr, len_ptr, cap) = self.triple_mut(); + let mut len = SetLenOnDrop::new(len_ptr); + while len.get() < cap { + if let Some(out) = iter.next() { + ptr::write(ptr.offset(len.get() as isize), out); + len.increment_len(1); + } else { + return; + } + } + } + + for elem in iter { + self.push(elem); + } + } +} + +impl Debug for SmallVec +where + A::Item: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() + } +} + +impl Default for SmallVec { + #[inline] + fn default() -> SmallVec { + SmallVec::new() + } +} + +#[cfg(feature = "may_dangle")] +unsafe impl<#[may_dangle] A: Array> Drop for SmallVec { + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } + } +} + +#[cfg(not(feature = "may_dangle"))] +impl Drop for SmallVec { + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } + } +} + +impl Clone for SmallVec +where + A::Item: Clone, +{ + fn clone(&self) -> SmallVec { + let mut new_vector = SmallVec::with_capacity(self.len()); + for element in self.iter() { + new_vector.push((*element).clone()) + } + new_vector + } +} + +impl PartialEq> for SmallVec +where + A::Item: PartialEq, +{ + #[inline] + fn eq(&self, other: &SmallVec) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &SmallVec) -> bool { + self[..] != other[..] + } +} + +impl Eq for SmallVec where A::Item: Eq {} + +impl PartialOrd for SmallVec +where + A::Item: PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &SmallVec) -> Option { + PartialOrd::partial_cmp(&**self, &**other) + } +} + +impl Ord for SmallVec +where + A::Item: Ord, +{ + #[inline] + fn cmp(&self, other: &SmallVec) -> Ordering { + Ord::cmp(&**self, &**other) + } +} + +impl Hash for SmallVec +where + A::Item: Hash, +{ + fn hash(&self, state: &mut H) { + (**self).hash(state) + } +} + +unsafe impl Send for SmallVec where A::Item: Send {} + +impl IntoIterator for SmallVec { + type IntoIter = IntoIter; + type Item = A::Item; + fn into_iter(mut self) -> Self::IntoIter { + unsafe { + // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements + let len = self.len(); + self.set_len(0); + IntoIter { + data: self, + current: 0, + end: len, + } + } + } +} + +impl<'a, A: Array> IntoIterator for &'a SmallVec { + type IntoIter = slice::Iter<'a, A::Item>; + type Item = &'a A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl<'a, A: Array> IntoIterator for &'a mut SmallVec { + type IntoIter = slice::IterMut<'a, A::Item>; + type Item = &'a mut A::Item; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} diff --git a/src/small_vec_data.rs b/src/small_vec_data.rs new file mode 100644 index 0000000..00fcd27 --- /dev/null +++ b/src/small_vec_data.rs @@ -0,0 +1,99 @@ +#[cfg(not(feature = "const_generics"))] +use crate::Array; +use core::{mem::MaybeUninit, ptr::NonNull}; + +#[cfg(feature = "union")] +pub union SmallVecData { + inline: MaybeUninit, + heap: (NonNull, usize), +} + +#[cfg(feature = "union")] +impl SmallVecData { + #[inline] + pub unsafe fn inline(&self) -> &A { + &*self.inline.as_ptr() + } + #[inline] + pub unsafe fn inline_mut(&mut self) -> &mut A { + &mut *self.inline.as_mut_ptr() + } + #[inline] + pub fn from_inline(inline: MaybeUninit) -> SmallVecData { + SmallVecData { inline } + } + #[inline] + pub unsafe fn into_inline(self) -> A { + self.inline.assume_init() + } + #[inline] + pub unsafe fn heap(&self) -> (*mut A::Item, usize) { + (self.heap.0.as_ptr(), self.heap.1) + } + #[inline] + pub unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { + (self.heap.0.as_ptr(), &mut self.heap.1) + } + #[inline] + pub fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { + SmallVecData { + heap: (NonNull::new(ptr).unwrap(), len), + } + } +} + +#[cfg(not(feature = "union"))] +pub enum SmallVecData { + Inline(MaybeUninit), + Heap((NonNull, usize)), +} + +#[cfg(not(feature = "union"))] +impl SmallVecData { + #[inline] + pub unsafe fn inline(&self) -> &A { + match *self { + SmallVecData::Inline(ref a) => &*a.as_ptr(), + _ => debug_unreachable!(), + } + } + #[inline] + pub unsafe fn inline_mut(&mut self) -> &mut A { + match *self { + SmallVecData::Inline(ref mut a) => &mut *a.as_mut_ptr(), + _ => debug_unreachable!(), + } + } + #[inline] + pub fn from_inline(inline: MaybeUninit) -> SmallVecData { + SmallVecData::Inline(inline) + } + #[inline] + pub unsafe fn into_inline(self) -> A { + match self { + SmallVecData::Inline(a) => a.assume_init(), + _ => debug_unreachable!(), + } + } + #[inline] + pub unsafe fn heap(&self) -> (*mut A::Item, usize) { + match *self { + SmallVecData::Heap(data) => (data.0.as_ptr(), data.1), + _ => debug_unreachable!(), + } + } + #[inline] + pub unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { + match *self { + SmallVecData::Heap(ref mut data) => (data.0.as_ptr(), &mut data.1), + _ => debug_unreachable!(), + } + } + #[inline] + pub fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { + SmallVecData::Heap((NonNull::new(ptr).unwrap(), len)) + } +} + +unsafe impl Send for SmallVecData {} +unsafe impl Sync for SmallVecData {} diff --git a/src/small_vec_visitor.rs b/src/small_vec_visitor.rs new file mode 100644 index 0000000..61a47a9 --- /dev/null +++ b/src/small_vec_visitor.rs @@ -0,0 +1,36 @@ +#[cfg(not(feature = "const_generics"))] +use crate::Array; +use crate::SmallVec; +use core::{fmt, marker::PhantomData}; +use serde::de::{Deserialize, SeqAccess, Visitor}; + +#[cfg(feature = "serde")] +pub struct SmallVecVisitor { + pub(crate) phantom: PhantomData, +} + +#[cfg(feature = "serde")] +impl<'de, A: Array> Visitor<'de> for SmallVecVisitor +where + A::Item: Deserialize<'de>, +{ + type Value = SmallVec; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("a sequence") + } + + fn visit_seq(self, mut seq: B) -> Result + where + B: SeqAccess<'de>, + { + let len = seq.size_hint().unwrap_or(0); + let mut values = SmallVec::with_capacity(len); + + while let Some(value) = seq.next_element()? { + values.push(value); + } + + Ok(values) + } +} diff --git a/src/spec_from.rs b/src/spec_from.rs new file mode 100644 index 0000000..26077a5 --- /dev/null +++ b/src/spec_from.rs @@ -0,0 +1,7 @@ +#[cfg(not(feature = "const_generics"))] +use crate::Array; +use crate::SmallVec; + +pub trait SpecFrom { + fn spec_from(slice: S) -> SmallVec; +} diff --git a/src/tests.rs b/src/tests.rs new file mode 100644 index 0000000..f7a2893 --- /dev/null +++ b/src/tests.rs @@ -0,0 +1,753 @@ +extern crate alloc; + +use crate::SmallVec; +use alloc::{boxed::Box, rc::Rc}; +use core::iter::FromIterator; + +#[test] +pub fn test_zero() { + let mut v = SmallVec::<[_; 0]>::new(); + assert!(!v.spilled()); + v.push(0usize); + assert!(v.spilled()); + assert_eq!(&*v, &[0]); +} + +// We heap allocate all these strings so that double frees will show up under valgrind. + +#[test] +pub fn test_inline() { + let mut v = SmallVec::<[_; 16]>::new(); + v.push("hello"); + v.push("there"); + assert_eq!(&*v, &["hello", "there",][..]); +} + +#[test] +pub fn test_spill() { + let mut v = SmallVec::<[_; 2]>::new(); + v.push("hello"); + assert_eq!(v[0], "hello"); + v.push("there"); + v.push("burma"); + assert_eq!(v[0], "hello"); + v.push("shave"); + assert_eq!(&*v, &["hello", "there", "burma", "shave",][..]); +} + +#[test] +pub fn test_double_spill() { + let mut v = SmallVec::<[_; 2]>::new(); + v.push("hello"); + v.push("there"); + v.push("burma"); + v.push("shave"); + v.push("hello"); + v.push("there"); + v.push("burma"); + v.push("shave"); + assert_eq!( + &*v, + &["hello", "there", "burma", "shave", "hello", "there", "burma", "shave",][..] + ); +} + +/// https://github.com/servo/rust-smallvec/issues/4 +#[test] +fn issue_4() { + SmallVec::<[Box; 2]>::new(); +} + +/// https://github.com/servo/rust-smallvec/issues/5 +#[test] +fn issue_5() { + assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some()); +} + +#[test] +fn test_with_capacity() { + let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(1); + assert!(v.is_empty()); + assert!(!v.spilled()); + assert_eq!(v.capacity(), 3); + + let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(10); + assert!(v.is_empty()); + assert!(v.spilled()); + assert_eq!(v.capacity(), 10); +} + +#[test] +fn drain() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().collect::>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().collect::>(), &[3, 4, 5]); +} + +#[test] +fn drain_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.drain().rev().collect::>(), &[3]); + + // spilling the vec + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.drain().rev().collect::>(), &[5, 4, 3]); +} + +#[test] +fn into_iter() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.into_iter().collect::>(), &[3]); + + // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.into_iter().collect::>(), &[3, 4, 5]); +} + +#[test] +fn into_iter_rev() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + assert_eq!(v.into_iter().rev().collect::>(), &[3]); + + // spilling the vec + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(3); + v.push(4); + v.push(5); + assert_eq!(v.into_iter().rev().collect::>(), &[5, 4, 3]); +} + +#[test] +fn into_iter_drop() { + use core::cell::Cell; + + struct DropCounter<'a>(&'a Cell); + + impl<'a> Drop for DropCounter<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.into_iter(); + assert_eq!(cell.get(), 1); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 2); + } + + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + assert!(v.into_iter().next().is_some()); + assert_eq!(cell.get(), 3); + } + { + let cell = Cell::new(0); + let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + v.push(DropCounter(&cell)); + { + let mut it = v.into_iter(); + assert!(it.next().is_some()); + assert!(it.next_back().is_some()); + } + assert_eq!(cell.get(), 3); + } +} + +#[test] +fn test_capacity() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.reserve(1); + assert_eq!(v.capacity(), 2); + assert!(!v.spilled()); + + v.reserve_exact(0x100); + assert!(v.capacity() >= 0x100); + + v.push(0); + v.push(1); + v.push(2); + v.push(3); + + v.shrink_to_fit(); + assert!(v.capacity() < 0x100); +} + +#[test] +fn test_truncate() { + let mut v: SmallVec<[Box; 8]> = SmallVec::new(); + + for x in 0..8 { + v.push(Box::new(x)); + } + v.truncate(4); + + assert_eq!(v.len(), 4); + assert!(!v.spilled()); + + assert_eq!(*v.swap_remove(1), 1); + assert_eq!(*v.remove(1), 3); + v.insert(1, Box::new(3)); + + assert_eq!(&v.iter().map(|v| **v).collect::>(), &[0, 3, 2]); +} + +#[test] +fn test_insert_many() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many(1, [5, 6].iter().cloned()); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); +} + +struct MockHintIter { + x: T, + hint: usize, +} +impl Iterator for MockHintIter { + type Item = T::Item; + fn next(&mut self) -> Option { + self.x.next() + } + fn size_hint(&self) -> (usize, Option) { + (self.hint, None) + } +} + +#[test] +fn test_insert_many_short_hint() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many( + 1, + MockHintIter { + x: [5, 6].iter().cloned(), + hint: 5, + }, + ); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); +} + +#[test] +fn test_insert_many_long_hint() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_many( + 1, + MockHintIter { + x: [5, 6].iter().cloned(), + hint: 1, + }, + ); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); +} + +#[test] +// https://github.com/servo/rust-smallvec/issues/96 +fn test_insert_many_panic() { + struct PanicOnDoubleDrop { + dropped: Box, + } + + impl Drop for PanicOnDoubleDrop { + fn drop(&mut self) { + assert!(!*self.dropped, "already dropped"); + *self.dropped = true; + } + } + + struct BadIter; + impl Iterator for BadIter { + type Item = PanicOnDoubleDrop; + fn size_hint(&self) -> (usize, Option) { + (1, None) + } + fn next(&mut self) -> Option { + panic!() + } + } + + let mut vec: SmallVec<[PanicOnDoubleDrop; 0]> = vec![ + PanicOnDoubleDrop { + dropped: Box::new(false), + }, + PanicOnDoubleDrop { + dropped: Box::new(false), + }, + ] + .into(); + let result = ::std::panic::catch_unwind(move || { + vec.insert_many(0, BadIter); + }); + assert!(result.is_err()); +} + +#[test] +#[should_panic] +fn test_invalid_grow() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + v.extend(0..8); + v.grow(5); +} + +#[test] +fn test_insert_from_slice() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.insert_from_slice(1, &[5, 6]); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 5, 6, 1, 2, 3] + ); +} + +#[test] +fn test_extend_from_slice() { + let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + for x in 0..4 { + v.push(x); + } + assert_eq!(v.len(), 4); + v.extend_from_slice(&[5, 6]); + assert_eq!( + &v.iter().map(|v| *v).collect::>(), + &[0, 1, 2, 3, 5, 6] + ); +} + +#[test] +#[should_panic] +fn test_drop_panic_smallvec() { + // This test should only panic once, and not double panic, + // which would mean a double drop + struct DropPanic; + + impl Drop for DropPanic { + fn drop(&mut self) { + panic!("drop"); + } + } + + let mut v = SmallVec::<[_; 1]>::new(); + v.push(DropPanic); +} + +#[test] +fn test_eq() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let mut b: SmallVec<[u32; 2]> = SmallVec::new(); + let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + // a = [1, 2] + a.push(1); + a.push(2); + // b = [1, 2] + b.push(1); + b.push(2); + // c = [3, 4] + c.push(3); + c.push(4); + + assert!(a == b); + assert!(a != c); +} + +#[test] +fn test_ord() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let mut b: SmallVec<[u32; 2]> = SmallVec::new(); + let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + // a = [1] + a.push(1); + // b = [1, 1] + b.push(1); + b.push(1); + // c = [1, 2] + c.push(1); + c.push(2); + + assert!(a < b); + assert!(b > a); + assert!(b < c); + assert!(c > b); +} + +#[test] +fn test_hash() { + use std::collections::hash_map::DefaultHasher; + use std::hash::Hash; + + { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + let b = [1, 2]; + a.extend(b.iter().cloned()); + 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 = DefaultHasher::new(); + assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); + } +} + +#[test] +fn test_as_ref() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_ref(), [1]); + a.push(2); + assert_eq!(a.as_ref(), [1, 2]); + a.push(3); + assert_eq!(a.as_ref(), [1, 2, 3]); +} + +#[test] +fn test_as_mut() { + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.as_mut(), [1]); + a.push(2); + assert_eq!(a.as_mut(), [1, 2]); + a.push(3); + assert_eq!(a.as_mut(), [1, 2, 3]); + a.as_mut()[1] = 4; + assert_eq!(a.as_mut(), [1, 4, 3]); +} + +#[test] +fn test_borrow() { + use core::borrow::Borrow; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow(), [1]); + a.push(2); + assert_eq!(a.borrow(), [1, 2]); + a.push(3); + assert_eq!(a.borrow(), [1, 2, 3]); +} + +#[test] +fn test_borrow_mut() { + use core::borrow::BorrowMut; + + let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + a.push(1); + assert_eq!(a.borrow_mut(), [1]); + a.push(2); + assert_eq!(a.borrow_mut(), [1, 2]); + a.push(3); + assert_eq!(a.borrow_mut(), [1, 2, 3]); + BorrowMut::<[u32]>::borrow_mut(&mut a)[1] = 4; + assert_eq!(a.borrow_mut(), [1, 4, 3]); +} + +#[test] +fn test_from() { + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1][..])[..], [1]); + assert_eq!(&SmallVec::<[u32; 2]>::from(&[1, 2, 3][..])[..], [1, 2, 3]); + + let vec = vec![]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let array = [1]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from(array); + assert_eq!(&*small_vec, &[1]); + drop(small_vec); + + let array = [99; 128]; + let small_vec: SmallVec<[u8; 128]> = SmallVec::from(array); + assert_eq!(&*small_vec, vec![99u8; 128].as_slice()); + drop(small_vec); +} + +#[test] +fn test_from_slice() { + assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1][..])[..], [1]); + assert_eq!( + &SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], + [1, 2, 3] + ); +} + +#[test] +fn test_exact_size_iterator() { + let mut vec = SmallVec::<[u32; 2]>::from(&[1, 2, 3][..]); + assert_eq!(vec.clone().into_iter().len(), 3); + assert_eq!(vec.drain().len(), 3); +} + +#[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"); +} + +#[test] +fn test_into_vec() { + let vec = SmallVec::<[u8; 2]>::from_iter(0..2); + assert_eq!(vec.into_vec(), vec![0, 1]); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..3); + assert_eq!(vec.into_vec(), vec![0, 1, 2]); +} + +#[test] +fn test_into_inner() { + let vec = SmallVec::<[u8; 2]>::from_iter(0..2); + assert_eq!(vec.into_inner(), Ok([0, 1])); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..1); + assert_eq!(vec.clone().into_inner(), Err(vec)); + + let vec = SmallVec::<[u8; 2]>::from_iter(0..3); + assert_eq!(vec.clone().into_inner(), Err(vec)); +} + +#[test] +fn test_from_vec() { + let vec = vec![]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[]); + drop(small_vec); + + let vec = vec![1]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1]); + drop(small_vec); + + let vec = vec![1, 2, 3]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); + + let vec = vec![1, 2, 3, 4, 5]; + let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); + assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); + drop(small_vec); +} + +#[test] +fn test_retain() { + // Test inline data storate + let mut sv: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); + sv.retain(|&mut i| i != 3); + assert_eq!(sv.pop(), Some(4)); + assert_eq!(sv.pop(), Some(2)); + assert_eq!(sv.pop(), Some(1)); + assert_eq!(sv.pop(), None); + + // Test spilled data storage + let mut sv: SmallVec<[i32; 3]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); + sv.retain(|&mut i| i != 3); + assert_eq!(sv.pop(), Some(4)); + assert_eq!(sv.pop(), Some(2)); + assert_eq!(sv.pop(), Some(1)); + assert_eq!(sv.pop(), None); + + // Test that drop implementations are called for inline. + let one = Rc::new(1); + let mut sv: SmallVec<[Rc; 3]> = SmallVec::new(); + sv.push(Rc::clone(&one)); + assert_eq!(Rc::strong_count(&one), 2); + sv.retain(|_| false); + assert_eq!(Rc::strong_count(&one), 1); + + // Test that drop implementations are called for spilled data. + let mut sv: SmallVec<[Rc; 1]> = SmallVec::new(); + sv.push(Rc::clone(&one)); + sv.push(Rc::new(2)); + assert_eq!(Rc::strong_count(&one), 2); + sv.retain(|_| false); + assert_eq!(Rc::strong_count(&one), 1); +} + +#[test] +fn test_dedup() { + let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); + dupes.dedup(); + assert_eq!(&*dupes, &[1, 2, 3]); + + let mut empty: SmallVec<[i32; 5]> = SmallVec::new(); + empty.dedup(); + assert!(empty.is_empty()); + + let mut all_ones: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 1, 1, 1]); + all_ones.dedup(); + assert_eq!(all_ones.len(), 1); + + let mut no_dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 4, 5]); + no_dupes.dedup(); + assert_eq!(no_dupes.len(), 5); +} + +#[test] +fn test_resize() { + let mut v: SmallVec<[i32; 8]> = SmallVec::new(); + v.push(1); + v.resize(5, 0); + assert_eq!(v[..], [1, 0, 0, 0, 0][..]); + + v.resize(2, -1); + assert_eq!(v[..], [1, 0][..]); +} + +#[cfg(feature = "std")] +#[test] +fn test_write() { + use std::io::Write; + + let data = [1, 2, 3, 4, 5]; + + let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); + let len = small_vec.write(&data[..]).unwrap(); + assert_eq!(len, 5); + assert_eq!(small_vec.as_ref(), data.as_ref()); + + let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); + small_vec.write_all(&data[..]).unwrap(); + assert_eq!(small_vec.as_ref(), data.as_ref()); +} + +#[cfg(feature = "serde")] +extern crate bincode; + +#[cfg(feature = "serde")] +#[test] +fn test_serde() { + use self::bincode::{config, deserialize}; + let mut small_vec: SmallVec<[i32; 2]> = SmallVec::new(); + small_vec.push(1); + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); + small_vec.push(2); + // Spill the vec + small_vec.push(3); + small_vec.push(4); + // Check again after spilling. + let encoded = config().limit(100).serialize(&small_vec).unwrap(); + let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); + assert_eq!(small_vec, decoded); +} + +#[test] +fn grow_to_shrink() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(1); + v.push(2); + v.push(3); + assert!(v.spilled()); + v.clear(); + // Shrink to inline. + v.grow(2); + assert!(!v.spilled()); + assert_eq!(v.capacity(), 2); + assert_eq!(v.len(), 0); + v.push(4); + assert_eq!(v[..], [4]); +} + +#[test] +fn resumable_extend() { + let s = "a b c"; + // This iterator yields: (Some('a'), None, Some('b'), None, Some('c')), None + let it = s + .chars() + .scan(0, |_, ch| if ch.is_whitespace() { None } else { Some(ch) }); + let mut v: SmallVec<[char; 4]> = SmallVec::new(); + v.extend(it); + assert_eq!(v[..], ['a']); +} + +#[test] +fn grow_spilled_same_size() { + let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + v.push(0); + v.push(1); + v.push(2); + assert!(v.spilled()); + assert_eq!(v.capacity(), 4); + // grow with the same capacity + v.grow(4); + assert_eq!(v.capacity(), 4); + assert_eq!(v[..], [0, 1, 2]); +} diff --git a/src/utils.rs b/src/utils.rs new file mode 100644 index 0000000..fd9c17d --- /dev/null +++ b/src/utils.rs @@ -0,0 +1,17 @@ +use core::mem; + +pub unsafe fn deallocate(ptr: *mut T, capacity: usize) { + let _vec: Vec = Vec::from_raw_parts(ptr, 0, capacity); + // Let it drop. +} + +/// Hint to the optimizer that any code path which calls this function is +/// statically unreachable and can be removed. +/// +/// Equivalent to `std::hint::unreachable_unchecked` but works in older versions of Rust. +#[inline] +pub unsafe fn unreachable() -> ! { + enum Void {} + let x: &Void = mem::transmute(1usize); + match *x {} +} From 85440ce104e63717166dd2d327c80e12fe7531d5 Mon Sep 17 00:00:00 2001 From: Caio Date: Sat, 15 Jun 2019 21:39:56 -0300 Subject: [PATCH 11/24] Make use of core::hint::unreachable_unchecked --- src/macros.rs | 2 +- src/small_vec.rs | 5 +++-- src/utils.rs | 15 +-------------- 3 files changed, 5 insertions(+), 17 deletions(-) diff --git a/src/macros.rs b/src/macros.rs index f84f868..bde9888 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -6,7 +6,7 @@ macro_rules! debug_unreachable { }; ($e:expr) => { if cfg!(not(debug_assertions)) { - crate::utils::unreachable(); + core::hint::unreachable_unchecked(); } else { panic!($e); } diff --git a/src/small_vec.rs b/src/small_vec.rs index 46f3acc..1dd2248 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -2,7 +2,7 @@ use crate::small_vec_visitor::SmallVecVisitor; #[cfg(feature = "specialization")] use crate::spec_from::SpecFrom; -use crate::utils::{deallocate, unreachable}; +use crate::utils::deallocate; #[cfg(not(feature = "const_generics"))] use crate::Array; use crate::{ @@ -13,6 +13,7 @@ use core::{ cmp::{Eq, Ord, Ordering, PartialOrd}, fmt::{self, Debug}, hash::{Hash, Hasher}, + hint::unreachable_unchecked, iter::{repeat, FromIterator}, mem::{self, MaybeUninit}, ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}, @@ -435,7 +436,7 @@ impl SmallVec { pub fn swap_remove(&mut self, index: usize) -> A::Item { let len = self.len(); self.swap(len - 1, index); - self.pop().unwrap_or_else(|| unsafe { unreachable() }) + self.pop().unwrap_or_else(|| unsafe { unreachable_unchecked() }) } /// Remove all elements from the vector. diff --git a/src/utils.rs b/src/utils.rs index fd9c17d..1a765c2 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,17 +1,4 @@ -use core::mem; - pub unsafe fn deallocate(ptr: *mut T, capacity: usize) { let _vec: Vec = Vec::from_raw_parts(ptr, 0, capacity); // Let it drop. -} - -/// Hint to the optimizer that any code path which calls this function is -/// statically unreachable and can be removed. -/// -/// Equivalent to `std::hint::unreachable_unchecked` but works in older versions of Rust. -#[inline] -pub unsafe fn unreachable() -> ! { - enum Void {} - let x: &Void = mem::transmute(1usize); - match *x {} -} +} \ No newline at end of file From 94b2383d7c1af003842911e5dadfaf87ff85b76a Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 16 Jun 2019 07:50:32 -0300 Subject: [PATCH 12/24] Adds the const_generics feature --- src/into_iter.rs | 40 ++- src/small_vec.rs | 737 ++++++++++++++++++++++----------------- src/small_vec_data.rs | 73 ++-- src/small_vec_visitor.rs | 23 +- src/spec_from.rs | 18 +- 5 files changed, 539 insertions(+), 352 deletions(-) diff --git a/src/into_iter.rs b/src/into_iter.rs index 1a62b64..16e69aa 100644 --- a/src/into_iter.rs +++ b/src/into_iter.rs @@ -3,28 +3,39 @@ use crate::Array; use crate::SmallVec; use core::ptr; +macro_rules! create_with_parts { +( + <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?>, + $array_item:ty +) => { + /// An iterator that consumes a `SmallVec` and yields its items by value. /// /// Returned from [`SmallVec::into_iter`][1]. /// /// [1]: struct.SmallVec.html#method.into_iter -pub struct IntoIter { - pub(crate) data: SmallVec, +pub struct IntoIter<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { + pub(crate) data: SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?>, pub(crate) current: usize, pub(crate) end: usize, } -impl Drop for IntoIter { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Drop + for IntoIter<$s_decl_ty$(, {$s_decl_const_ty})?> +{ fn drop(&mut self) { for _ in self {} } } -impl Iterator for IntoIter { - type Item = A::Item; +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Iterator + for IntoIter<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + type Item = $array_item; #[inline] - fn next(&mut self) -> Option { + fn next(&mut self) -> Option<$array_item> { if self.current == self.end { None } else { @@ -43,9 +54,11 @@ impl Iterator for IntoIter { } } -impl DoubleEndedIterator for IntoIter { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> DoubleEndedIterator + for IntoIter<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn next_back(&mut self) -> Option { + fn next_back(&mut self) -> Option<$array_item> { if self.current == self.end { None } else { @@ -57,4 +70,13 @@ impl DoubleEndedIterator for IntoIter { } } -impl ExactSizeIterator for IntoIter {} +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> ExactSizeIterator + for IntoIter<$s_decl_ty$(, {$s_decl_const_ty})?> {} + + } +} + +#[cfg(feature = "const_generics")] +create_with_parts!(, , T); +#[cfg(not(feature = "const_generics"))] +create_with_parts!(, , A::Item); diff --git a/src/small_vec.rs b/src/small_vec.rs index 1dd2248..3186a05 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -29,6 +29,15 @@ use std::io; #[cfg(feature = "serde")] use std::marker::PhantomData; +macro_rules! create_with_parts { +( + <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?>, + $array:ty, + $array_item:ty, + $array_size:expr +) => { + /// 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 @@ -55,23 +64,21 @@ use std::marker::PhantomData; /// assert_eq!(v.len(), 5); /// assert!(v.spilled()); /// ``` -pub struct SmallVec { +pub struct SmallVec<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { // The capacity field is used to determine which of the storage variants is active: - // If capacity <= A::size() then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use). - // If capacity > A::size() then the heap variant is used and capacity holds the size of the memory allocation. + // If capacity <= $array_size then the inline variant is used and capacity holds the current length of the vector (number of elements actually in use). + // If capacity > $array_size then the heap variant is used and capacity holds the size of the memory allocation. capacity: usize, - data: SmallVecData, + data: SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?>, } -impl SmallVec { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> { /// Construct an empty vector #[inline] - pub fn new() -> SmallVec { - unsafe { - SmallVec { - capacity: 0, - data: SmallVecData::from_inline(mem::uninitialized()), - } + pub fn new() -> Self { + SmallVec { + capacity: 0, + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()), } } @@ -90,14 +97,14 @@ impl SmallVec { /// ``` #[inline] pub fn with_capacity(n: usize) -> Self { - let mut v = SmallVec::new(); + let mut v = Self::new(); v.reserve_exact(n); v } - /// Construct a new `SmallVec` from a `Vec`. + /// Construct a new `SmallVec` from a `Vec<$array_item>`. /// - /// Elements will be copied to the inline buffer if vec.capacity() <= A::size(). + /// Elements will be copied to the inline buffer if vec.capacity() <= $array_size. /// /// ```rust /// use smallvec::SmallVec; @@ -108,10 +115,10 @@ impl SmallVec { /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` #[inline] - pub fn from_vec(mut vec: Vec) -> SmallVec { - if vec.capacity() <= A::size() { + pub fn from_vec(mut vec: Vec<$array_item>) -> Self { + if vec.capacity() <= $array_size { unsafe { - let mut data = SmallVecData::::from_inline(mem::uninitialized()); + let mut data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); let len = vec.len(); vec.set_len(0); ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().as_mut_ptr(), len); @@ -127,7 +134,7 @@ impl SmallVec { SmallVec { capacity: cap, - data: SmallVecData::from_heap(ptr, len), + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_heap(ptr, len), } } } @@ -144,10 +151,10 @@ impl SmallVec { /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` #[inline] - pub fn from_buf(buf: A) -> SmallVec { + pub fn from_buf(buf: $array) -> Self { SmallVec { - capacity: A::size(), - data: SmallVecData::from_inline(MaybeUninit::new(buf)), + capacity: $array_size, + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::new(buf)), } } @@ -164,14 +171,14 @@ impl SmallVec { /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` #[inline] - pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec { - assert!(len <= A::size()); - unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) } + pub fn from_buf_and_len(buf: $array, len: usize) -> Self { + assert!(len <= $array_size); + unsafe { Self::from_buf_and_len_unchecked(buf, len) } } /// Constructs a new `SmallVec` on the stack from an `A` without /// copying elements. Also sets the length. The user is responsible - /// for ensuring that `len <= A::size()`. + /// for ensuring that `len <= $array_size`. /// /// ```rust /// use smallvec::SmallVec; @@ -184,10 +191,10 @@ impl SmallVec { /// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); /// ``` #[inline] - pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec { + pub unsafe fn from_buf_and_len_unchecked(buf: $array, len: usize) -> Self { SmallVec { capacity: len, - data: SmallVecData::from_inline(MaybeUninit::new(buf)), + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::new(buf)), } } @@ -204,7 +211,7 @@ impl SmallVec { /// The maximum number of elements this vector can hold inline #[inline] pub fn inline_size(&self) -> usize { - A::size() + $array_size } /// The number of elements stored in the vector @@ -228,20 +235,20 @@ impl SmallVec { /// Returns a tuple with (data ptr, len, capacity) /// Useful to get all SmallVec properties with a single check of the current storage variant. #[inline] - fn triple(&self) -> (*const A::Item, usize, usize) { + fn triple(&self) -> (*const $array_item, usize, usize) { unsafe { if self.spilled() { let (ptr, len) = self.data.heap(); (ptr, len, self.capacity) } else { - (self.data.inline().as_ptr(), self.capacity, A::size()) + (self.data.inline().as_ptr(), self.capacity, $array_size) } } } /// Returns a tuple with (data ptr, len ptr, capacity) #[inline] - fn triple_mut(&mut self) -> (*mut A::Item, &mut usize, usize) { + fn triple_mut(&mut self) -> (*mut $array_item, &mut usize, usize) { unsafe { if self.spilled() { let (ptr, len_ptr) = self.data.heap_mut(); @@ -250,7 +257,7 @@ impl SmallVec { ( self.data.inline_mut().as_mut_ptr(), &mut self.capacity, - A::size(), + $array_size, ) } } @@ -259,11 +266,11 @@ impl SmallVec { /// Returns `true` if the data has spilled into a separate heap-allocated buffer. #[inline] pub fn spilled(&self) -> bool { - self.capacity > A::size() + self.capacity > $array_size } /// Empty the vector and return an iterator over its former contents. - pub fn drain(&mut self) -> Drain { + pub fn drain(&mut self) -> Drain<$array_item> { unsafe { let ptr = self.as_mut_ptr(); @@ -280,7 +287,7 @@ impl SmallVec { /// Append an item to the vector. #[inline] - pub fn push(&mut self, value: A::Item) { + pub fn push(&mut self, value: $array_item) { unsafe { let (_, &mut len, cap) = self.triple_mut(); if len == cap { @@ -294,7 +301,7 @@ impl SmallVec { /// Remove an item from the end of the vector and return it, or None if empty. #[inline] - pub fn pop(&mut self) -> Option { + pub fn pop(&mut self) -> Option<$array_item> { unsafe { let (ptr, len_ptr, _) = self.triple_mut(); if *len_ptr == 0 { @@ -318,7 +325,7 @@ impl SmallVec { if unspilled { return; } - self.data = SmallVecData::from_inline(mem::uninitialized()); + self.data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); self.capacity = len; } else if new_cap != cap { @@ -326,7 +333,7 @@ impl SmallVec { let new_alloc = vec.as_mut_ptr(); mem::forget(vec); ptr::copy_nonoverlapping(ptr, new_alloc, len); - self.data = SmallVecData::from_heap(new_alloc, len); + self.data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_heap(new_alloc, len); self.capacity = new_cap; if unspilled { return; @@ -385,7 +392,7 @@ impl SmallVec { if self.inline_size() >= len { unsafe { let (ptr, len) = self.data.heap(); - self.data = SmallVecData::from_inline(mem::uninitialized()); + self.data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); deallocate(ptr, self.capacity); self.capacity = len; @@ -416,14 +423,14 @@ impl SmallVec { /// Extracts a slice containing the entire vector. /// /// Equivalent to `&s[..]`. - pub fn as_slice(&self) -> &[A::Item] { + pub fn as_slice(&self) -> &[$array_item] { self } /// Extracts a mutable slice of the entire vector. /// /// Equivalent to `&mut s[..]`. - pub fn as_mut_slice(&mut self) -> &mut [A::Item] { + pub fn as_mut_slice(&mut self) -> &mut [$array_item] { self } @@ -433,7 +440,7 @@ impl SmallVec { /// /// Panics if `index` is out of bounds. #[inline] - pub fn swap_remove(&mut self, index: usize) -> A::Item { + pub fn swap_remove(&mut self, index: usize) -> $array_item { let len = self.len(); self.swap(len - 1, index); self.pop().unwrap_or_else(|| unsafe { unreachable_unchecked() }) @@ -449,7 +456,7 @@ impl SmallVec { /// left. /// /// Panics if `index` is out of bounds. - pub fn remove(&mut self, index: usize) -> A::Item { + pub fn remove(&mut self, index: usize) -> $array_item { unsafe { let (mut ptr, len_ptr, _) = self.triple_mut(); let len = *len_ptr; @@ -465,7 +472,7 @@ impl SmallVec { /// 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) { + pub fn insert(&mut self, index: usize, element: $array_item) { self.reserve(1); unsafe { @@ -481,7 +488,7 @@ impl SmallVec { /// Insert multiple elements at position `index`, shifting all following elements toward the /// back. - pub fn insert_many>(&mut self, index: usize, iterable: I) { + pub fn insert_many>(&mut self, index: usize, iterable: I) { let iter = iterable.into_iter(); if index == self.len() { return self.extend(iter); @@ -531,7 +538,7 @@ impl SmallVec { /// Convert a SmallVec to a Vec, without reallocating if the SmallVec has already spilled onto /// the heap. - pub fn into_vec(self) -> Vec { + pub fn into_vec(self) -> Vec<$array_item> { if self.spilled() { unsafe { let (ptr, len) = self.data.heap(); @@ -548,8 +555,8 @@ impl SmallVec { /// /// This method returns `Err(Self)` if the SmallVec is too short (and the `A` contains uninitialized elements), /// or if the SmallVec is too long (and all the elements were spilled to the heap). - pub fn into_inner(self) -> Result { - if self.spilled() || self.len() != A::size() { + pub fn into_inner(self) -> Result<$array, Self> { + if self.spilled() || self.len() != $array_size { Err(self) } else { unsafe { @@ -565,7 +572,7 @@ impl SmallVec { /// In other words, remove all elements `e` such that `f(&e)` returns `false`. /// This method operates in place and preserves the order of the retained /// elements. - pub fn retain bool>(&mut self, mut f: F) { + pub fn retain bool>(&mut self, mut f: F) { let mut del = 0; let len = self.len(); for i in 0..len { @@ -581,7 +588,7 @@ impl SmallVec { /// Removes consecutive duplicate elements. pub fn dedup(&mut self) where - A::Item: PartialEq, + $array_item: PartialEq<$array_item>, { self.dedup_by(|a, b| a == b); } @@ -589,7 +596,7 @@ impl SmallVec { /// Removes consecutive duplicate elements using the given equality relation. pub fn dedup_by(&mut self, mut same_bucket: F) where - F: FnMut(&mut A::Item, &mut A::Item) -> bool, + F: FnMut(&mut $array_item, &mut $array_item) -> bool, { // See the implementation of Vec::dedup_by in the // standard library for an explanation of this algorithm. @@ -621,7 +628,7 @@ impl SmallVec { /// Removes consecutive elements that map to the same key. pub fn dedup_by_key(&mut self, mut key: F) where - F: FnMut(&mut A::Item) -> K, + F: FnMut(&mut $array_item) -> K, K: PartialEq, { self.dedup_by(|a, b| key(a) == key(b)); @@ -638,7 +645,7 @@ impl SmallVec { /// * `ptr` needs to have been previously allocated via `SmallVec` for its /// spilled storage (at least, it's highly likely to be incorrect if it /// wasn't). - /// * `ptr`'s `A::Item` type needs to be the same size and alignment that + /// * `ptr`'s `$array_item` type needs to be the same size and alignment that /// it was allocated with /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated @@ -695,29 +702,76 @@ impl SmallVec { /// assert_eq!(&*rebuilt, &[4, 5, 6]); /// } /// } - pub unsafe fn from_raw_parts(ptr: *mut A::Item, length: usize, capacity: usize) -> SmallVec { - assert!(capacity > A::size()); + pub unsafe fn from_raw_parts(ptr: *mut $array_item, length: usize, capacity: usize) -> Self { + assert!(capacity > $array_size); SmallVec { capacity, - data: SmallVecData::from_heap(ptr, length), + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_heap(ptr, length), } } } -impl SmallVec +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> + SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Copy, + $array_item: Clone, +{ + /// Resizes the vector so that its length is equal to `len`. + /// + /// If `len` is less than the current length, the vector simply truncated. + /// + /// If `len` is greater than the current length, `value` is appended to the + /// vector until its length equals `len`. + pub fn resize(&mut self, len: usize, value: $array_item) { + let old_len = self.len(); + + if len > old_len { + self.extend(repeat(value).take(len - old_len)); + } else { + self.truncate(len); + } + } + + /// Creates a `SmallVec` with `n` copies of `elem`. + /// ``` + /// use smallvec::SmallVec; + /// + /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); + /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); + /// ``` + pub fn from_elem(elem: $array_item, n: usize) -> Self { + if n > $array_size { + vec![elem; n].into() + } else { + let mut v = Self::new(); + unsafe { + let (ptr, len_ptr, _) = v.triple_mut(); + let mut local_len = SetLenOnDrop::new(len_ptr); + + for i in 0..n as isize { + core::ptr::write(ptr.offset(i), elem.clone()); + local_len.increment_len(1); + } + } + v + } + } +} + +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Copy, { /// Copy the elements from a slice into a new `SmallVec`. /// /// For slices of `Copy` types, this is more efficient than `SmallVec::from(slice)`. - pub fn from_slice(slice: &[A::Item]) -> Self { + pub fn from_slice(slice: &[$array_item]) -> Self { let len = slice.len(); - if len <= A::size() { + if len <= $array_size { SmallVec { capacity: len, - data: SmallVecData::from_inline(unsafe { - let mut data = MaybeUninit::::uninit(); + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(unsafe { + let mut data = MaybeUninit::<$array>::uninit(); let slice_mut = &mut *data.as_mut_ptr(); ptr::copy_nonoverlapping(slice.as_ptr(), slice_mut.as_mut_ptr(), len); data @@ -729,7 +783,7 @@ where mem::forget(b); SmallVec { capacity: cap, - data: SmallVecData::from_heap(ptr, len), + data: SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_heap(ptr, len), } } } @@ -737,7 +791,7 @@ where /// elements toward the back. /// /// For slices of `Copy` types, this is more efficient than `insert`. - pub fn insert_from_slice(&mut self, index: usize, slice: &[A::Item]) { + pub fn insert_from_slice(&mut self, index: usize, slice: &[$array_item]) { self.reserve(slice.len()); let len = self.len(); @@ -756,145 +810,144 @@ where /// /// For slices of `Copy` types, this is more efficient than `extend`. #[inline] - pub fn extend_from_slice(&mut self, slice: &[A::Item]) { + pub fn extend_from_slice(&mut self, slice: &[$array_item]) { let len = self.len(); self.insert_from_slice(len, slice); } } -impl SmallVec -where - A::Item: Clone, +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> AsMut<[$array_item]> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> { - /// Resizes the vector so that its length is equal to `len`. - /// - /// If `len` is less than the current length, the vector simply truncated. - /// - /// If `len` is greater than the current length, `value` is appended to the - /// vector until its length equals `len`. - pub fn resize(&mut self, len: usize, value: A::Item) { - let old_len = self.len(); - - if len > old_len { - self.extend(repeat(value).take(len - old_len)); - } else { - self.truncate(len); - } - } - - /// Creates a `SmallVec` with `n` copies of `elem`. - /// ``` - /// use smallvec::SmallVec; - /// - /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); - /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); - /// ``` - pub fn from_elem(elem: A::Item, n: usize) -> Self { - if n > A::size() { - vec![elem; n].into() - } else { - let mut v = SmallVec::::new(); - unsafe { - let (ptr, len_ptr, _) = v.triple_mut(); - let mut local_len = SetLenOnDrop::new(len_ptr); - - for i in 0..n as isize { - core::ptr::write(ptr.offset(i), elem.clone()); - local_len.increment_len(1); - } - } - v - } + #[inline] + fn as_mut(&mut self) -> &mut [$array_item] { + self } } -impl Deref for SmallVec { - type Target = [A::Item]; + +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> AsRef<[$array_item]> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn deref(&self) -> &[A::Item] { - unsafe { - let (ptr, len, _) = self.triple(); - slice::from_raw_parts(ptr, len) - } + fn as_ref(&self) -> &[$array_item] { + self } } -impl DerefMut for SmallVec { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Borrow<[$array_item]> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn deref_mut(&mut self) -> &mut [A::Item] { - unsafe { - let (ptr, &mut len, _) = self.triple_mut(); - slice::from_raw_parts_mut(ptr, len) - } + fn borrow(&self) -> &[$array_item] { + self } } -impl AsRef<[A::Item]> for SmallVec { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> BorrowMut<[$array_item]> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn as_ref(&self) -> &[A::Item] { + fn borrow_mut(&mut self) -> &mut [$array_item] { self } } -impl AsMut<[A::Item]> for SmallVec { - #[inline] - fn as_mut(&mut self) -> &mut [A::Item] { - self +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Clone + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Clone, +{ + fn clone(&self) -> Self { + let mut new_vector = Self::with_capacity(self.len()); + for element in self.iter() { + new_vector.push((*element).clone()) + } + new_vector } } -impl Borrow<[A::Item]> for SmallVec { - #[inline] - fn borrow(&self) -> &[A::Item] { - self +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Debug + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } -impl BorrowMut<[A::Item]> for SmallVec { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Default + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn borrow_mut(&mut self) -> &mut [A::Item] { - self + fn default() -> Self { + Self::new() } } -#[cfg(feature = "std")] -impl> io::Write for SmallVec { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Deref + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + type Target = [$array_item]; #[inline] - fn write(&mut self, buf: &[u8]) -> io::Result { - self.extend_from_slice(buf); - Ok(buf.len()) + fn deref(&self) -> &[$array_item] { + unsafe { + let (ptr, len, _) = self.triple(); + slice::from_raw_parts(ptr, len) + } } +} +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> DerefMut + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ #[inline] - fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { - self.extend_from_slice(buf); - Ok(()) + fn deref_mut(&mut self) -> &mut [$array_item] { + unsafe { + let (ptr, &mut len, _) = self.triple_mut(); + slice::from_raw_parts_mut(ptr, len) + } } +} - #[inline] - fn flush(&mut self) -> io::Result<()> { - Ok(()) +#[cfg(feature = "may_dangle")] +unsafe impl<#[may_dangle] $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Drop + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } + } } } -#[cfg(feature = "serde")] -impl Serialize for SmallVec -where - A::Item: Serialize, +#[cfg(not(feature = "may_dangle"))] +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Drop + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> { - fn serialize(&self, serializer: S) -> Result { - let mut state = serializer.serialize_seq(Some(self.len()))?; - for item in self { - state.serialize_element(&item)?; + fn drop(&mut self) { + unsafe { + if self.spilled() { + let (ptr, len) = self.data.heap(); + Vec::from_raw_parts(ptr, len, self.capacity); + } else { + ptr::drop_in_place(&mut self[..]); + } } - state.end() } } #[cfg(feature = "serde")] -impl<'de, A: Array> Deserialize<'de> for SmallVec +impl<'de, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Deserialize<'de> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Deserialize<'de>, + $array_item: Deserialize<'de>, { fn deserialize>(deserializer: D) -> Result { deserializer.deserialize_seq(SmallVecVisitor { @@ -903,183 +956,229 @@ where } } -#[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Eq + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Clone, + $array_item: Eq {} + +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Extend<$array_item> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> { - #[inline] - default fn spec_from(slice: &'a [A::Item]) -> SmallVec { - slice.into_iter().cloned().collect() + fn extend>(&mut self, iterable: I) { + let mut iter = iterable.into_iter(); + let (lower_size_bound, _) = iter.size_hint(); + self.reserve(lower_size_bound); + + unsafe { + let (ptr, len_ptr, cap) = self.triple_mut(); + let mut len = SetLenOnDrop::new(len_ptr); + while len.get() < cap { + if let Some(out) = iter.next() { + ptr::write(ptr.offset(len.get() as isize), out); + len.increment_len(1); + } else { + return; + } + } + } + + for elem in iter { + self.push(elem); + } } } -#[cfg(feature = "specialization")] -impl<'a, A: Array> SpecFrom for SmallVec +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> ExtendFromSlice<$array_item> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Copy, + $array_item: Copy, +{ + fn extend_from_slice(&mut self, other: &[$array_item]) { + Self::extend_from_slice(self, other) + } +} + +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> From<$array> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + #[inline] + fn from(array: $array) -> Self { + Self::from_buf(array) + } +} + +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> From> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> { #[inline] - fn spec_from(slice: &'a [A::Item]) -> SmallVec { - SmallVec::from_slice(slice) + fn from(vec: Vec<$array_item>) -> Self { + Self::from_vec(vec) } } -impl<'a, A: Array> From<&'a [A::Item]> for SmallVec +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> From<&'a [$array_item]> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Clone, + $array_item: Clone, { #[cfg(not(feature = "specialization"))] #[inline] - fn from(slice: &'a [A::Item]) -> SmallVec { + fn from(slice: &'a [$array_item]) -> Self { slice.into_iter().cloned().collect() } #[cfg(feature = "specialization")] #[inline] - fn from(slice: &'a [A::Item]) -> SmallVec { - SmallVec::spec_from(slice) + fn from(slice: &'a [$array_item]) -> Self { + Self::spec_from(slice) } } -impl From> for SmallVec { - #[inline] - fn from(vec: Vec) -> SmallVec { - SmallVec::from_vec(vec) +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> FromIterator<$array_item> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + fn from_iter>(iterable: I) -> Self { + let mut v = Self::new(); + v.extend(iterable); + v } } -impl From for SmallVec { - #[inline] - fn from(array: A) -> SmallVec { - SmallVec::from_buf(array) +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Hash + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Hash, +{ + fn hash(&self, state: &mut H) { + (**self).hash(state) } } -macro_rules! impl_index { - ($index_type: ty, $output_type: ty) => { - impl Index<$index_type> for SmallVec { - type Output = $output_type; - #[inline] - fn index(&self, index: $index_type) -> &$output_type { - &(&**self)[index] +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> IntoIterator + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + type IntoIter = IntoIter<$s_decl_ty$(, {$s_decl_const_ty})?>; + type Item = $array_item; + fn into_iter(mut self) -> Self::IntoIter { + unsafe { + // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements + let len = self.len(); + self.set_len(0); + IntoIter { + data: self, + current: 0, + end: len, } } + } +} - impl IndexMut<$index_type> for SmallVec { - #[inline] - fn index_mut(&mut self, index: $index_type) -> &mut $output_type { - &mut (&mut **self)[index] - } - } - }; +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> IntoIterator + for &'a SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + type IntoIter = slice::Iter<'a, $array_item>; + type Item = &'a $array_item; + fn into_iter(self) -> Self::IntoIter { + self.iter() + } } -impl_index!(usize, A::Item); -impl_index!(Range, [A::Item]); -impl_index!(RangeFrom, [A::Item]); -impl_index!(RangeTo, [A::Item]); -impl_index!(RangeFull, [A::Item]); +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> IntoIterator + for &'a mut SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +{ + type IntoIter = slice::IterMut<'a, $array_item>; + type Item = &'a mut $array_item; + fn into_iter(self) -> Self::IntoIter { + self.iter_mut() + } +} -impl ExtendFromSlice for SmallVec +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Ord + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Copy, + $array_item: Ord, { - fn extend_from_slice(&mut self, other: &[A::Item]) { - SmallVec::extend_from_slice(self, other) + #[inline] + fn cmp(&self, other: &Self) -> Ordering { + Ord::cmp(&**self, &**other) } } -impl FromIterator for SmallVec { - fn from_iter>(iterable: I) -> SmallVec { - let mut v = SmallVec::new(); - v.extend(iterable); - v +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> PartialOrd + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: PartialOrd, +{ + #[inline] + fn partial_cmp(&self, other: &Self) -> Option { + PartialOrd::partial_cmp(&**self, &**other) } } -impl Extend for SmallVec { - fn extend>(&mut self, iterable: I) { - let mut iter = iterable.into_iter(); - let (lower_size_bound, _) = iter.size_hint(); - self.reserve(lower_size_bound); +unsafe impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Send + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Send {} - unsafe { - let (ptr, len_ptr, cap) = self.triple_mut(); - let mut len = SetLenOnDrop::new(len_ptr); - while len.get() < cap { - if let Some(out) = iter.next() { - ptr::write(ptr.offset(len.get() as isize), out); - len.increment_len(1); - } else { - return; - } - } - } - for elem in iter { - self.push(elem); +#[cfg(feature = "serde")] +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Serialize + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Serialize, +{ + fn serialize(&self, serializer: S) -> Result { + let mut state = serializer.serialize_seq(Some(self.len()))?; + for item in self { + state.serialize_element(&item)?; } + state.end() } } -impl Debug for SmallVec +#[cfg(feature = "specialization")] +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SpecFrom + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Debug, + $array_item: Clone, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.debug_list().entries(self.iter()).finish() - } -} - -impl Default for SmallVec { #[inline] - fn default() -> SmallVec { - SmallVec::new() + default fn spec_from(slice: &'a [$array_item]) -> Self { + slice.into_iter().cloned().collect() } } -#[cfg(feature = "may_dangle")] -unsafe impl<#[may_dangle] A: Array> Drop for SmallVec { - fn drop(&mut self) { - unsafe { - if self.spilled() { - let (ptr, len) = self.data.heap(); - Vec::from_raw_parts(ptr, len, self.capacity); - } else { - ptr::drop_in_place(&mut self[..]); - } - } +#[cfg(feature = "specialization")] +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SpecFrom + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Copy, +{ + #[inline] + fn spec_from(slice: &'a [$array_item]) -> Self { + Self::from_slice(slice) } } -#[cfg(not(feature = "may_dangle"))] -impl Drop for SmallVec { - fn drop(&mut self) { - unsafe { - if self.spilled() { - let (ptr, len) = self.data.heap(); - Vec::from_raw_parts(ptr, len, self.capacity); - } else { - ptr::drop_in_place(&mut self[..]); - } - } } } -impl Clone for SmallVec +#[cfg(feature = "const_generics")] +impl PartialEq for SmallVec where - A::Item: Clone, + T: PartialEq { - fn clone(&self) -> SmallVec { - let mut new_vector = SmallVec::with_capacity(self.len()); - for element in self.iter() { - new_vector.push((*element).clone()) - } - new_vector + #[inline] + fn eq(&self, other: &Self) -> bool { + self[..] == other[..] + } + #[inline] + fn ne(&self, other: &Self) -> bool { + self[..] != other[..] } } +#[cfg(not(feature = "const_generics"))] impl PartialEq> for SmallVec where A::Item: PartialEq, @@ -1094,68 +1193,80 @@ where } } -impl Eq for SmallVec where A::Item: Eq {} - -impl PartialOrd for SmallVec -where - A::Item: PartialOrd, +#[cfg(all(feature = "std", feature = "const_generics"))] +impl io::Write for SmallVec { #[inline] - fn partial_cmp(&self, other: &SmallVec) -> Option { - PartialOrd::partial_cmp(&**self, &**other) + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) } -} -impl Ord for SmallVec -where - A::Item: Ord, -{ #[inline] - fn cmp(&self, other: &SmallVec) -> Ordering { - Ord::cmp(&**self, &**other) + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) } -} -impl Hash for SmallVec -where - A::Item: Hash, -{ - fn hash(&self, state: &mut H) { - (**self).hash(state) + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) } } -unsafe impl Send for SmallVec where A::Item: Send {} +#[cfg(all(feature = "std", not(feature = "const_generics")))] +impl> io::Write for SmallVec { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + self.extend_from_slice(buf); + Ok(buf.len()) + } -impl IntoIterator for SmallVec { - type IntoIter = IntoIter; - type Item = A::Item; - fn into_iter(mut self) -> Self::IntoIter { - unsafe { - // Set SmallVec len to zero as `IntoIter` drop handles dropping of the elements - let len = self.len(); - self.set_len(0); - IntoIter { - data: self, - current: 0, - end: len, - } - } + #[inline] + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + self.extend_from_slice(buf); + Ok(()) } -} -impl<'a, A: Array> IntoIterator for &'a SmallVec { - type IntoIter = slice::Iter<'a, A::Item>; - type Item = &'a A::Item; - fn into_iter(self) -> Self::IntoIter { - self.iter() + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) } } -impl<'a, A: Array> IntoIterator for &'a mut SmallVec { - type IntoIter = slice::IterMut<'a, A::Item>; - type Item = &'a mut A::Item; - fn into_iter(self) -> Self::IntoIter { - self.iter_mut() +#[cfg(not(feature = "const_generics"))] +macro_rules! impl_index { + ($index_type: ty, $output_type: ty) => { + impl Index<$index_type> for SmallVec { + type Output = $output_type; + #[inline] + fn index(&self, index: $index_type) -> &$output_type { + &(&**self)[index] + } + } + + impl IndexMut<$index_type> for SmallVec { + #[inline] + fn index_mut(&mut self, index: $index_type) -> &mut $output_type { + &mut (&mut **self)[index] + } + } } } + +#[cfg(not(feature = "const_generics"))] +impl_index!(usize, A::Item); +#[cfg(not(feature = "const_generics"))] +impl_index!(Range, [A::Item]); +#[cfg(not(feature = "const_generics"))] +impl_index!(RangeFrom, [A::Item]); +#[cfg(not(feature = "const_generics"))] +impl_index!(RangeTo, [A::Item]); +#[cfg(not(feature = "const_generics"))] +impl_index!(RangeFull, [A::Item]); + +#[cfg(feature = "const_generics")] +create_with_parts!(, , [T; N], T, N); +#[cfg(not(feature = "const_generics"))] +create_with_parts!(, , A, A::Item, A::size()); + diff --git a/src/small_vec_data.rs b/src/small_vec_data.rs index 00fcd27..b743a84 100644 --- a/src/small_vec_data.rs +++ b/src/small_vec_data.rs @@ -2,40 +2,48 @@ use crate::Array; use core::{mem::MaybeUninit, ptr::NonNull}; +macro_rules! create_with_parts { +( + <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?>, + $array:ty, + $array_item:ty +) => { + #[cfg(feature = "union")] -pub union SmallVecData { - inline: MaybeUninit, - heap: (NonNull, usize), +pub union SmallVecData<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { + inline: MaybeUninit<$s_decl_ty$(, {$s_decl_const_ty})?>, + heap: (NonNull<$array_item>, usize), } #[cfg(feature = "union")] -impl SmallVecData { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> { #[inline] - pub unsafe fn inline(&self) -> &A { + pub unsafe fn inline(&self) -> &$array { &*self.inline.as_ptr() } #[inline] - pub unsafe fn inline_mut(&mut self) -> &mut A { + pub unsafe fn inline_mut(&mut self) -> &mut $array { &mut *self.inline.as_mut_ptr() } #[inline] - pub fn from_inline(inline: MaybeUninit) -> SmallVecData { + pub fn from_inline(inline: MaybeUninit<$array>) -> Self { SmallVecData { inline } } #[inline] - pub unsafe fn into_inline(self) -> A { + pub unsafe fn into_inline(self) -> $array { self.inline.assume_init() } #[inline] - pub unsafe fn heap(&self) -> (*mut A::Item, usize) { + pub unsafe fn heap(&self) -> (*mut $array_item, usize) { (self.heap.0.as_ptr(), self.heap.1) } #[inline] - pub unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { + pub unsafe fn heap_mut(&mut self) -> (*mut $array_item, &mut usize) { (self.heap.0.as_ptr(), &mut self.heap.1) } #[inline] - pub fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { + pub fn from_heap(ptr: *mut $array_item, len: usize) -> Self { SmallVecData { heap: (NonNull::new(ptr).unwrap(), len), } @@ -43,57 +51,74 @@ impl SmallVecData { } #[cfg(not(feature = "union"))] -pub enum SmallVecData { - Inline(MaybeUninit), - Heap((NonNull, usize)), +pub enum SmallVecData<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { + Inline(MaybeUninit<$array>), + Heap((NonNull<$array_item>, usize)), } #[cfg(not(feature = "union"))] -impl SmallVecData { +impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> { #[inline] - pub unsafe fn inline(&self) -> &A { + pub unsafe fn inline(&self) -> &$array { match *self { SmallVecData::Inline(ref a) => &*a.as_ptr(), _ => debug_unreachable!(), } } #[inline] - pub unsafe fn inline_mut(&mut self) -> &mut A { + pub unsafe fn inline_mut(&mut self) -> &mut $array { match *self { SmallVecData::Inline(ref mut a) => &mut *a.as_mut_ptr(), _ => debug_unreachable!(), } } #[inline] - pub fn from_inline(inline: MaybeUninit) -> SmallVecData { + pub fn from_inline(inline: MaybeUninit<$array>) -> Self { SmallVecData::Inline(inline) } #[inline] - pub unsafe fn into_inline(self) -> A { + pub unsafe fn into_inline(self) -> $array { match self { SmallVecData::Inline(a) => a.assume_init(), _ => debug_unreachable!(), } } #[inline] - pub unsafe fn heap(&self) -> (*mut A::Item, usize) { + pub unsafe fn heap(&self) -> (*mut $array_item, usize) { match *self { SmallVecData::Heap(data) => (data.0.as_ptr(), data.1), _ => debug_unreachable!(), } } #[inline] - pub unsafe fn heap_mut(&mut self) -> (*mut A::Item, &mut usize) { + pub unsafe fn heap_mut(&mut self) -> (*mut $array_item, &mut usize) { match *self { SmallVecData::Heap(ref mut data) => (data.0.as_ptr(), &mut data.1), _ => debug_unreachable!(), } } #[inline] - pub fn from_heap(ptr: *mut A::Item, len: usize) -> SmallVecData { + pub fn from_heap(ptr: *mut $array_item, len: usize) -> Self { SmallVecData::Heap((NonNull::new(ptr).unwrap(), len)) } } -unsafe impl Send for SmallVecData {} -unsafe impl Sync for SmallVecData {} +unsafe impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Send + for SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Send +{} + +unsafe impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Sync + for SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> +where + $array_item: Send +{} + + } +} + +#[cfg(feature = "const_generics")] +create_with_parts!(, , [T; N], T); +#[cfg(not(feature = "const_generics"))] +create_with_parts!(, , A, A::Item); diff --git a/src/small_vec_visitor.rs b/src/small_vec_visitor.rs index 61a47a9..d480ed0 100644 --- a/src/small_vec_visitor.rs +++ b/src/small_vec_visitor.rs @@ -4,17 +4,24 @@ use crate::SmallVec; use core::{fmt, marker::PhantomData}; use serde::de::{Deserialize, SeqAccess, Visitor}; +macro_rules! create_with_parts { + ( + <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?> +) => { + #[cfg(feature = "serde")] -pub struct SmallVecVisitor { - pub(crate) phantom: PhantomData, +pub struct SmallVecVisitor<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { + pub(crate) phantom: PhantomData<$s_decl_ty$(, {$s_decl_const_ty})?>, } #[cfg(feature = "serde")] -impl<'de, A: Array> Visitor<'de> for SmallVecVisitor +impl<'de, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Visitor<'de> + for SmallVecVisitor<$s_decl_ty$(, {$s_decl_const_ty})?> where A::Item: Deserialize<'de>, { - type Value = SmallVec; + type Value = SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?>; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { formatter.write_str("a sequence") @@ -34,3 +41,11 @@ where Ok(values) } } + + } +} + +#[cfg(feature = "const_generics")] +create_with_parts!(, ); +#[cfg(not(feature = "const_generics"))] +create_with_parts!(, ); diff --git a/src/spec_from.rs b/src/spec_from.rs index 26077a5..699f7f6 100644 --- a/src/spec_from.rs +++ b/src/spec_from.rs @@ -2,6 +2,20 @@ use crate::Array; use crate::SmallVec; -pub trait SpecFrom { - fn spec_from(slice: S) -> SmallVec; +macro_rules! create_with_parts { + ( + <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?> +) => { + +pub trait SpecFrom<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*, S> { + fn spec_from(slice: S) -> SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?>; +} + + } } + +#[cfg(feature = "const_generics")] +create_with_parts!(); +#[cfg(not(feature = "const_generics"))] +create_with_parts!(, ); From 20633740dbdd87748f4e1c8fed1324bb3395906f Mon Sep 17 00:00:00 2001 From: Caio Date: Sun, 16 Jun 2019 07:50:44 -0300 Subject: [PATCH 13/24] Adjust documentation --- src/lib.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 876a2e7..1a011ff 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,14 +8,10 @@ //! 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. //! -//! ## no_std support +//! ## `alloc` support //! -//! By default, `smallvec` depends on `libstd`. However, it can be configured to use the unstable -//! `liballoc` API instead, for use on platforms that have `liballoc` but not `libstd`. This -//! configuration is currently unstable and is not guaranteed to work on all versions of Rust. -//! -//! To depend on `smallvec` without `libstd`, use `default-features = false` in the `smallvec` -//! section of Cargo.toml to disable its `"alloc"` feature. +//! By default, `smallvec` uses the `alloc` crate, which means that it can be used on platforms +//! that have `liballoc` but not `libstd`. //! //! ## `union` feature //! From 557c4c7d11c28b9e863ed800b4964279d606d51a Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 19 Jun 2019 16:14:49 -0300 Subject: [PATCH 14/24] Clippy --- src/array.rs | 2 +- src/into_iter.rs | 2 +- src/set_len_on_drop.rs | 2 +- src/small_vec.rs | 57 +++++++++++++++++++----------------------- src/utils.rs | 2 +- 5 files changed, 30 insertions(+), 35 deletions(-) diff --git a/src/array.rs b/src/array.rs index 7f7a096..2e0b8d4 100644 --- a/src/array.rs +++ b/src/array.rs @@ -26,5 +26,5 @@ macro_rules! impl_array( impl_array!( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 24, 32, 36, 0x40, 0x80, 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000, 0x10000, 0x20000, 0x40000, 0x80000, - 0x100000 + 0x100_000 ); diff --git a/src/into_iter.rs b/src/into_iter.rs index 16e69aa..2a10e84 100644 --- a/src/into_iter.rs +++ b/src/into_iter.rs @@ -64,7 +64,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> DoubleEndedIte } else { unsafe { self.end -= 1; - Some(ptr::read(self.data.as_ptr().offset(self.end as isize))) + Some(ptr::read(self.data.as_ptr().add(self.end))) } } } diff --git a/src/set_len_on_drop.rs b/src/set_len_on_drop.rs index 55c3ff0..10f4311 100644 --- a/src/set_len_on_drop.rs +++ b/src/set_len_on_drop.rs @@ -11,7 +11,7 @@ impl<'a> SetLenOnDrop<'a> { pub fn new(len: &'a mut usize) -> Self { SetLenOnDrop { local_len: *len, - len: len, + len, } } diff --git a/src/small_vec.rs b/src/small_vec.rs index 3186a05..1360069 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -295,7 +295,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de } let (ptr, len_ptr, _) = self.triple_mut(); *len_ptr = len + 1; - ptr::write(ptr.offset(len as isize), value); + ptr::write(ptr.add(len), value); } } @@ -309,7 +309,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de } let last_index = *len_ptr - 1; *len_ptr = last_index; - Some(ptr::read(ptr.offset(last_index as isize))) + Some(ptr::read(ptr.add(last_index))) } } @@ -415,7 +415,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de while len < *len_ptr { let last_index = *len_ptr - 1; *len_ptr = last_index; - ptr::drop_in_place(ptr.offset(last_index as isize)); + ptr::drop_in_place(ptr.add(last_index)); } } } @@ -462,9 +462,9 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de let len = *len_ptr; assert!(index < len); *len_ptr = len - 1; - ptr = ptr.offset(index as isize); + ptr = ptr.add(index); let item = ptr::read(ptr); - ptr::copy(ptr.offset(1), ptr, len - index - 1); + ptr::copy(ptr.add(1), ptr, len - index - 1); item } } @@ -480,8 +480,8 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de let len = *len_ptr; assert!(index <= len); *len_ptr = len + 1; - ptr = ptr.offset(index as isize); - ptr::copy(ptr, ptr.offset(1), len - index); + ptr = ptr.add(index); + ptr::copy(ptr, ptr.add(1), len - index); ptr::write(ptr, element); } } @@ -502,23 +502,23 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de unsafe { let old_len = self.len(); assert!(index <= old_len); - let mut ptr = self.as_mut_ptr().offset(index as isize); + let mut ptr = self.as_mut_ptr().add(index); // Move the trailing elements. - ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index); + ptr::copy(ptr, ptr.add(lower_size_bound), old_len - index); // In case the iterator panics, don't double-drop the items we just copied above. self.set_len(index); let mut num_added = 0; for element in iter { - let mut cur = ptr.offset(num_added as isize); + let mut cur = ptr.add(num_added); if num_added >= lower_size_bound { // Iterator provided more elements than the hint. Move trailing items again. self.reserve(1); - ptr = self.as_mut_ptr().offset(index as isize); - cur = ptr.offset(num_added as isize); - ptr::copy(cur, cur.offset(1), old_len - index); + ptr = self.as_mut_ptr().add(index); + cur = ptr.add(num_added); + ptr::copy(cur, cur.add(1), old_len - index); } ptr::write(cur, element); num_added += 1; @@ -526,8 +526,8 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de if num_added < lower_size_bound { // Iterator provided fewer elements than the hint ptr::copy( - ptr.offset(lower_size_bound as isize), - ptr.offset(num_added as isize), + ptr.add(lower_size_bound), + ptr.add(num_added), old_len - index, ); } @@ -610,11 +610,11 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de unsafe { for r in 1..len { - let p_r = ptr.offset(r as isize); - let p_wm1 = ptr.offset((w - 1) as isize); + let p_r = ptr.add(r); + let p_wm1 = ptr.add(w - 1); if !same_bucket(&mut *p_r, &mut *p_wm1) { if r != w { - let p_w = p_wm1.offset(1); + let p_w = p_wm1.add(1); mem::swap(&mut *p_r, &mut *p_w); } w += 1; @@ -692,8 +692,8 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de /// // writing into the old `SmallVec`'s inline storage on the /// // stack. /// assert!(spilled); - /// for i in 0..len as isize { - /// ptr::write(p.offset(i), 4 + i); + /// for i in 0..len { + /// ptr::write(p.add(i), 4 + i); /// } /// /// // Put everything back together into a SmallVec with a different @@ -748,8 +748,8 @@ where let (ptr, len_ptr, _) = v.triple_mut(); let mut local_len = SetLenOnDrop::new(len_ptr); - for i in 0..n as isize { - core::ptr::write(ptr.offset(i), elem.clone()); + for i in 0..n { + core::ptr::write(ptr.add(i), elem.clone()); local_len.increment_len(1); } } @@ -799,8 +799,8 @@ where unsafe { let slice_ptr = slice.as_ptr(); - let ptr = self.as_mut_ptr().offset(index as isize); - ptr::copy(ptr, ptr.offset(slice.len() as isize), len - index); + let ptr = self.as_mut_ptr().add(index); + ptr::copy(ptr, ptr.add(slice.len()), len - index); ptr::copy_nonoverlapping(slice_ptr, ptr, slice.len()); self.set_len(len + slice.len()); } @@ -974,7 +974,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Extend<$array_ let mut len = SetLenOnDrop::new(len_ptr); while len.get() < cap { if let Some(out) = iter.next() { - ptr::write(ptr.offset(len.get() as isize), out); + ptr::write(ptr.add(len.get()), out); len.increment_len(1); } else { return; @@ -1187,10 +1187,6 @@ where fn eq(&self, other: &SmallVec) -> bool { self[..] == other[..] } - #[inline] - fn ne(&self, other: &SmallVec) -> bool { - self[..] != other[..] - } } #[cfg(all(feature = "std", feature = "const_generics"))] @@ -1251,7 +1247,7 @@ macro_rules! impl_index { &mut (&mut **self)[index] } } - } + }; } #[cfg(not(feature = "const_generics"))] @@ -1269,4 +1265,3 @@ impl_index!(RangeFull, [A::Item]); create_with_parts!(, , [T; N], T, N); #[cfg(not(feature = "const_generics"))] create_with_parts!(, , A, A::Item, A::size()); - diff --git a/src/utils.rs b/src/utils.rs index 1a765c2..0468584 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,4 +1,4 @@ pub unsafe fn deallocate(ptr: *mut T, capacity: usize) { let _vec: Vec = Vec::from_raw_parts(ptr, 0, capacity); // Let it drop. -} \ No newline at end of file +} From 950e3e355137d045b674372d37721e37aeee3f56 Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 19 Jun 2019 16:41:05 -0300 Subject: [PATCH 15/24] Return a pointer in `inline` and `inline_mut` --- src/small_vec.rs | 10 +++++----- src/small_vec_data.rs | 16 ++++++++-------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/small_vec.rs b/src/small_vec.rs index 1360069..5c8ef96 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -121,7 +121,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de let mut data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); let len = vec.len(); vec.set_len(0); - ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().as_mut_ptr(), len); + ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len); SmallVec { capacity: len, @@ -241,7 +241,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de let (ptr, len) = self.data.heap(); (ptr, len, self.capacity) } else { - (self.data.inline().as_ptr(), self.capacity, $array_size) + (self.data.inline(), self.capacity, $array_size) } } } @@ -255,7 +255,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de (ptr, len_ptr, self.capacity) } else { ( - self.data.inline_mut().as_mut_ptr(), + self.data.inline_mut(), &mut self.capacity, $array_size, ) @@ -326,7 +326,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de return; } self.data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len); self.capacity = len; } else if new_cap != cap { let mut vec = Vec::with_capacity(new_cap); @@ -393,7 +393,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de unsafe { let (ptr, len) = self.data.heap(); self.data = SmallVecData::<$s_decl_ty$(, {$s_decl_const_ty})?>::from_inline(MaybeUninit::uninit()); - ptr::copy_nonoverlapping(ptr, self.data.inline_mut().as_mut_ptr(), len); + ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len); deallocate(ptr, self.capacity); self.capacity = len; } diff --git a/src/small_vec_data.rs b/src/small_vec_data.rs index b743a84..17b915c 100644 --- a/src/small_vec_data.rs +++ b/src/small_vec_data.rs @@ -19,12 +19,12 @@ pub union SmallVecData<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?) #[cfg(feature = "union")] impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> { #[inline] - pub unsafe fn inline(&self) -> &$array { - &*self.inline.as_ptr() + pub unsafe fn inline(&self) -> *const $array_item { + (*self.inline.as_ptr()).as_ptr() } #[inline] - pub unsafe fn inline_mut(&mut self) -> &mut $array { - &mut *self.inline.as_mut_ptr() + pub unsafe fn inline_mut(&mut self) -> *mut $array_item { + (*self.inline.as_mut_ptr()).as_mut_ptr() } #[inline] pub fn from_inline(inline: MaybeUninit<$array>) -> Self { @@ -59,16 +59,16 @@ pub enum SmallVecData<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?), #[cfg(not(feature = "union"))] impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVecData<$s_decl_ty$(, {$s_decl_const_ty})?> { #[inline] - pub unsafe fn inline(&self) -> &$array { + pub unsafe fn inline(&self) -> *const $array_item { match *self { - SmallVecData::Inline(ref a) => &*a.as_ptr(), + SmallVecData::Inline(ref a) => (*a.as_ptr()).as_ptr(), _ => debug_unreachable!(), } } #[inline] - pub unsafe fn inline_mut(&mut self) -> &mut $array { + pub unsafe fn inline_mut(&mut self) -> *mut $array_item { match *self { - SmallVecData::Inline(ref mut a) => &mut *a.as_mut_ptr(), + SmallVecData::Inline(ref mut a) => (*a.as_mut_ptr()).as_mut_ptr(), _ => debug_unreachable!(), } } From d7b235281cd82fac747a8a9d5a94c7fe8ef8fa25 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 11:24:31 -0300 Subject: [PATCH 16/24] Enable 1.36 on Travis --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 77d1f0c..42f0019 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,9 @@ language: rust rust: - #- 1.36.0 + - 1.36.0 - nightly - beta - #- stable + - stable script: - pushd ./scripts - ./test-stable.sh From 90dcc25630b59f1883367221476902a7fd9b578f Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 11:26:24 -0300 Subject: [PATCH 17/24] Re-enable no_std --- src/extend_from_slice.rs | 2 ++ src/lib.rs | 3 +++ src/macros.rs | 10 ++-------- src/small_vec.rs | 16 +++++++--------- src/tests.rs | 9 +++++---- src/utils.rs | 2 ++ 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/extend_from_slice.rs b/src/extend_from_slice.rs index ad6a975..9d2899b 100644 --- a/src/extend_from_slice.rs +++ b/src/extend_from_slice.rs @@ -1,3 +1,5 @@ +use alloc::vec::Vec; + /// Trait to be implemented by a collection that can be extended from a slice /// /// ## Example diff --git a/src/lib.rs b/src/lib.rs index 1a011ff..bf20354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,8 +28,11 @@ #![cfg_attr(feature = "may_dangle", feature(dropck_eyepatch))] #![cfg_attr(feature = "specialization", feature(specialization))] #![cfg_attr(feature = "union", feature(untagged_unions))] +#![cfg_attr(not(feature = "std"), no_std)] #![deny(missing_docs)] +extern crate alloc; + #[cfg(not(feature = "const_generics"))] mod array; mod drain; diff --git a/src/macros.rs b/src/macros.rs index bde9888..1ced4d7 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -21,25 +21,19 @@ macro_rules! debug_unreachable { /// - Create a [`SmallVec`] containing a given list of elements: /// /// ``` -/// # #[macro_use] extern crate smallvec; -/// # use smallvec::SmallVec; -/// # fn main() { +/// use smallvec::{smallvec, SmallVec}; /// let v: SmallVec<[_; 128]> = smallvec![1, 2, 3]; /// assert_eq!(v[0], 1); /// assert_eq!(v[1], 2); /// assert_eq!(v[2], 3); -/// # } /// ``` /// /// - Create a [`SmallVec`] from a given element and size: /// /// ``` -/// # #[macro_use] extern crate smallvec; -/// # use smallvec::SmallVec; -/// # fn main() { +/// use smallvec::{smallvec, SmallVec}; /// let v: SmallVec<[_; 0x8000]> = smallvec![1; 3]; /// assert_eq!(v, SmallVec::from_buf([1, 1, 1])); -/// # } /// ``` /// /// Note that unlike array expressions this syntax supports all elements diff --git a/src/small_vec.rs b/src/small_vec.rs index 5c8ef96..273cf34 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -8,6 +8,9 @@ use crate::Array; use crate::{ set_len_on_drop::SetLenOnDrop, small_vec_data::SmallVecData, Drain, ExtendFromSlice, IntoIter, }; +use alloc::{vec, vec::Vec}; +#[cfg(feature = "serde")] +use core::marker::PhantomData; use core::{ borrow::{Borrow, BorrowMut}, cmp::{Eq, Ord, Ordering, PartialOrd}, @@ -26,8 +29,6 @@ use serde::{ }; #[cfg(feature = "std")] use std::io; -#[cfg(feature = "serde")] -use std::marker::PhantomData; macro_rules! create_with_parts { ( @@ -667,10 +668,8 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de /// # Examples /// /// ``` - /// # #[macro_use] extern crate smallvec; - /// # use smallvec::SmallVec; - /// use std::mem; - /// use std::ptr; + /// use core::{mem, ptr}; + /// use smallvec::{smallvec, SmallVec}; /// /// fn main() { /// let mut v: SmallVec<[_; 1]> = smallvec![1, 2, 3]; @@ -1166,7 +1165,7 @@ where #[cfg(feature = "const_generics")] impl PartialEq for SmallVec where - T: PartialEq + T: PartialEq, { #[inline] fn eq(&self, other: &Self) -> bool { @@ -1190,8 +1189,7 @@ where } #[cfg(all(feature = "std", feature = "const_generics"))] -impl io::Write for SmallVec -{ +impl io::Write for SmallVec { #[inline] fn write(&mut self, buf: &[u8]) -> io::Result { self.extend_from_slice(buf); diff --git a/src/tests.rs b/src/tests.rs index f7a2893..fff321d 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,7 @@ extern crate alloc; use crate::SmallVec; -use alloc::{boxed::Box, rc::Rc}; +use alloc::{boxed::Box, rc::Rc, vec, vec::Vec}; use core::iter::FromIterator; #[test] @@ -290,6 +290,7 @@ fn test_insert_many_long_hint() { ); } +#[cfg(feature = "std")] #[test] // https://github.com/servo/rust-smallvec/issues/96 fn test_insert_many_panic() { @@ -324,7 +325,7 @@ fn test_insert_many_panic() { }, ] .into(); - let result = ::std::panic::catch_unwind(move || { + let result = std::panic::catch_unwind(move || { vec.insert_many(0, BadIter); }); assert!(result.is_err()); @@ -422,10 +423,10 @@ fn test_ord() { assert!(c > b); } +#[cfg(feature = "std")] #[test] fn test_hash() { - use std::collections::hash_map::DefaultHasher; - use std::hash::Hash; + use std::{collections::hash_map::DefaultHasher, hash::Hash}; { let mut a: SmallVec<[u32; 2]> = SmallVec::new(); diff --git a/src/utils.rs b/src/utils.rs index 0468584..31e9ce3 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,3 +1,5 @@ +use alloc::vec::Vec; + pub unsafe fn deallocate(ptr: *mut T, capacity: usize) { let _vec: Vec = Vec::from_raw_parts(ptr, 0, capacity); // Let it drop. From cd02cd3a110242a189196bd457af7440ccdf0915 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 11:30:53 -0300 Subject: [PATCH 18/24] Enable all-features on docs.rs --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b875416..da27a95 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,9 @@ readme = "README.md" repository = "https://github.com/servo/rust-smallvec" version = "0.6.10" +[package.metadata.docs.rs] +all-features = true + [dependencies] serde = { version = "1", optional = true } @@ -22,4 +25,4 @@ const_generics = [] may_dangle = [] specialization = [] std = [] -union = [] \ No newline at end of file +union = [] From 4cc4d372bbd0016410c3121c0909792f8d9bba07 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 11:51:13 -0300 Subject: [PATCH 19/24] Fix some constant generics errors --- src/small_vec.rs | 6 ++++-- src/small_vec_data.rs | 2 +- src/small_vec_visitor.rs | 13 +++++++------ src/spec_from.rs | 6 +++--- 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/src/small_vec.rs b/src/small_vec.rs index 273cf34..8515d9f 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -1136,7 +1136,8 @@ where } #[cfg(feature = "specialization")] -impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SpecFrom +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> + SpecFrom<&'a [$array_item], $s_decl_ty$(, {$s_decl_const_ty})?> for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where $array_item: Clone, @@ -1148,7 +1149,8 @@ where } #[cfg(feature = "specialization")] -impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SpecFrom +impl<'a, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> + SpecFrom<&'a [$array_item], $s_decl_ty$(, {$s_decl_const_ty})?> for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> where $array_item: Copy, diff --git a/src/small_vec_data.rs b/src/small_vec_data.rs index 17b915c..39eb675 100644 --- a/src/small_vec_data.rs +++ b/src/small_vec_data.rs @@ -12,7 +12,7 @@ macro_rules! create_with_parts { #[cfg(feature = "union")] pub union SmallVecData<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { - inline: MaybeUninit<$s_decl_ty$(, {$s_decl_const_ty})?>, + inline: MaybeUninit<$array>, heap: (NonNull<$array_item>, usize), } diff --git a/src/small_vec_visitor.rs b/src/small_vec_visitor.rs index d480ed0..0ebb715 100644 --- a/src/small_vec_visitor.rs +++ b/src/small_vec_visitor.rs @@ -5,21 +5,22 @@ use core::{fmt, marker::PhantomData}; use serde::de::{Deserialize, SeqAccess, Visitor}; macro_rules! create_with_parts { - ( +( <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, - <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?> + <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?>, + $array_item:ty ) => { #[cfg(feature = "serde")] pub struct SmallVecVisitor<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> { - pub(crate) phantom: PhantomData<$s_decl_ty$(, {$s_decl_const_ty})?>, + pub(crate) phantom: PhantomData<$s_decl_ty>, } #[cfg(feature = "serde")] impl<'de, $($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Visitor<'de> for SmallVecVisitor<$s_decl_ty$(, {$s_decl_const_ty})?> where - A::Item: Deserialize<'de>, + $array_item: Deserialize<'de>, { type Value = SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?>; @@ -46,6 +47,6 @@ where } #[cfg(feature = "const_generics")] -create_with_parts!(, ); +create_with_parts!(, , T); #[cfg(not(feature = "const_generics"))] -create_with_parts!(, ); +create_with_parts!(, , A::Item); diff --git a/src/spec_from.rs b/src/spec_from.rs index 699f7f6..64e491d 100644 --- a/src/spec_from.rs +++ b/src/spec_from.rs @@ -3,12 +3,12 @@ use crate::Array; use crate::SmallVec; macro_rules! create_with_parts { - ( +( <$($({$s_impl_ty_prefix:ident})? $s_impl_ty:ident$(: $s_impl_ty_bound:ident)?),*>, <$s_decl_ty:ident$(, {$s_decl_const_ty:ident})?> ) => { -pub trait SpecFrom<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*, S> { +pub trait SpecFrom { fn spec_from(slice: S) -> SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?>; } @@ -16,6 +16,6 @@ pub trait SpecFrom<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*, } #[cfg(feature = "const_generics")] -create_with_parts!(); +create_with_parts!(, ); #[cfg(not(feature = "const_generics"))] create_with_parts!(, ); From 4b2e32cd350b6255e6057c1193aeab099e5a0f0e Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 12:09:57 -0300 Subject: [PATCH 20/24] Fix modified tests there were using String --- src/tests.rs | 55 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/src/tests.rs b/src/tests.rs index fff321d..851fcb4 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,7 +1,5 @@ -extern crate alloc; - use crate::SmallVec; -use alloc::{boxed::Box, rc::Rc, vec, vec::Vec}; +use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec, vec::Vec}; use core::iter::FromIterator; #[test] @@ -18,37 +16,54 @@ pub fn test_zero() { #[test] pub fn test_inline() { let mut v = SmallVec::<[_; 16]>::new(); - v.push("hello"); - v.push("there"); - assert_eq!(&*v, &["hello", "there",][..]); + v.push("hello".to_owned()); + v.push("there".to_owned()); + assert_eq!(&*v, &["hello".to_owned(), "there".to_owned()][..]); } #[test] pub fn test_spill() { let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello"); + v.push("hello".to_owned()); assert_eq!(v[0], "hello"); - v.push("there"); - v.push("burma"); + v.push("there".to_owned()); + v.push("burma".to_owned()); assert_eq!(v[0], "hello"); - v.push("shave"); - assert_eq!(&*v, &["hello", "there", "burma", "shave",][..]); + v.push("shave".to_owned()); + assert_eq!( + &*v, + &[ + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned() + ][..] + ); } #[test] pub fn test_double_spill() { let mut v = SmallVec::<[_; 2]>::new(); - v.push("hello"); - v.push("there"); - v.push("burma"); - v.push("shave"); - v.push("hello"); - v.push("there"); - v.push("burma"); - v.push("shave"); + v.push("hello".to_owned()); + v.push("there".to_owned()); + v.push("burma".to_owned()); + v.push("shave".to_owned()); + v.push("hello".to_owned()); + v.push("there".to_owned()); + v.push("burma".to_owned()); + v.push("shave".to_owned()); assert_eq!( &*v, - &["hello", "there", "burma", "shave", "hello", "there", "burma", "shave",][..] + &[ + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned(), + "hello".to_owned(), + "there".to_owned(), + "burma".to_owned(), + "shave".to_owned() + ][..] ); } From 7aea5565776e554fd31a05fe4f41ee278bb00569 Mon Sep 17 00:00:00 2001 From: Caio Date: Thu, 4 Jul 2019 12:32:48 -0300 Subject: [PATCH 21/24] Do not use const_generics feature on docs.rs --- .travis.yml | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 42f0019..b90e11c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: rust rust: - 1.36.0 - - nightly - beta + - nightly - stable script: - pushd ./scripts diff --git a/Cargo.toml b/Cargo.toml index da27a95..61cca51 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ repository = "https://github.com/servo/rust-smallvec" version = "0.6.10" [package.metadata.docs.rs] -all-features = true +features = ["may_dangle", "specialization", "std", "union"] [dependencies] serde = { version = "1", optional = true } From 753869810f1a06de70ba17cb3fa46959be13cb58 Mon Sep 17 00:00:00 2001 From: Caio Date: Mon, 8 Jul 2019 14:07:41 -0300 Subject: [PATCH 22/24] Make constant generics work --- scripts/test-common.sh | 2 +- scripts/test-nightly.sh | 25 ++- src/lib.rs | 1 + src/small_vec.rs | 59 ++----- src/small_vec_index_impls.rs | 109 +++++++++++++ src/tests.rs | 308 ++++++++++++++++++----------------- 6 files changed, 305 insertions(+), 199 deletions(-) create mode 100644 src/small_vec_index_impls.rs diff --git a/scripts/test-common.sh b/scripts/test-common.sh index 75b56d2..eea935a 100644 --- a/scripts/test-common.sh +++ b/scripts/test-common.sh @@ -6,5 +6,5 @@ STABLE_FEATURES=( test_with_feature() { local feature=$1 /bin/echo -e "\e[0;33m***** Testing with feature '${feature}' *****\e[0m\n" - cargo test --features "${feature}" --no-default-features --verbose + CARGO_INCREMENTAL=0 cargo test --features "${feature}" --no-default-features --verbose } \ No newline at end of file diff --git a/scripts/test-nightly.sh b/scripts/test-nightly.sh index 0c03707..e62aff9 100755 --- a/scripts/test-nightly.sh +++ b/scripts/test-nightly.sh @@ -17,18 +17,27 @@ done # All nightly features individually with constant generics -# for feature in "${STABLE_FEATURES[@]}"; do -# test_with_feature "const_generic, $feature" -# done +# FIXME: Remove CARGO_INCREMENTAL. See https://github.com/rust-lang/rust/issues/61338 +# FIXME: Remove --lib once const_generics is default. Doctests are not using constant generics -# for feature in "${NIGHTLY_FEATURES[@]}"; do -# test_with_feature "const_generic, $feature" -# done +test_lib_with_feature() { + local feature=$1 + /bin/echo -e "\e[0;33m***** Testing with feature '${feature}' *****\e[0m\n" + CARGO_INCREMENTAL=0 cargo test --features "${feature}" --lib --no-default-features --verbose +} + +for feature in "${STABLE_FEATURES[@]}"; do + test_lib_with_feature "const_generics, $feature" +done + +for feature in "${NIGHTLY_FEATURES[@]}"; do + test_lib_with_feature "const_generics, $feature" +done # All features -# /bin/echo -e "\e[0;33m***** Testing all features *****\e[0m\n" -# cargo test --all-features --no-default-features --verbose +/bin/echo -e "\e[0;33m***** Testing all features *****\e[0m\n" +CARGO_INCREMENTAL=0 cargo test --all-features --lib --no-default-features --verbose # Run bench diff --git a/src/lib.rs b/src/lib.rs index bf20354..9e40548 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,6 +43,7 @@ mod macros; mod set_len_on_drop; mod small_vec; mod small_vec_data; +mod small_vec_index_impls; #[cfg(feature = "serde")] mod small_vec_visitor; #[cfg(feature = "specialization")] diff --git a/src/small_vec.rs b/src/small_vec.rs index 8515d9f..8ba9e6b 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -1,5 +1,3 @@ -#[cfg(feature = "serde")] -use crate::small_vec_visitor::SmallVecVisitor; #[cfg(feature = "specialization")] use crate::spec_from::SpecFrom; use crate::utils::deallocate; @@ -9,8 +7,6 @@ use crate::{ set_len_on_drop::SetLenOnDrop, small_vec_data::SmallVecData, Drain, ExtendFromSlice, IntoIter, }; use alloc::{vec, vec::Vec}; -#[cfg(feature = "serde")] -use core::marker::PhantomData; use core::{ borrow::{Borrow, BorrowMut}, cmp::{Eq, Ord, Ordering, PartialOrd}, @@ -19,16 +15,20 @@ use core::{ hint::unreachable_unchecked, iter::{repeat, FromIterator}, mem::{self, MaybeUninit}, - ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}, + ops::{Deref, DerefMut}, ptr, slice, }; -#[cfg(feature = "serde")] -use serde::{ - de::{Deserialize, Deserializer}, - ser::{Serialize, SerializeSeq, Serializer}, -}; #[cfg(feature = "std")] use std::io; +#[cfg(feature = "serde")] +use { + crate::small_vec_visitor::SmallVecVisitor, + core::marker::PhantomData, + serde::{ + de::{Deserialize, Deserializer}, + ser::{Serialize, SerializeSeq, Serializer}, + }, +}; macro_rules! create_with_parts { ( @@ -47,13 +47,13 @@ macro_rules! create_with_parts { /// /// 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. +/// array. For example a `SmallVec<[u64; 8]>`/`SmallVec` can hold up to eight 64-bit integers inline. /// /// ## Example /// /// ```rust /// use smallvec::SmallVec; -/// let mut v = SmallVec::<[u8; 4]>::new(); // initialize an empty vector +/// let mut v: SmallVec<[u8; 4]> = SmallVec::new(); // initialize an empty vector /// /// // The vector can hold up to 4 items without spilling onto the heap. /// v.extend(0..4); @@ -697,7 +697,7 @@ impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> SmallVec<$s_de /// /// // Put everything back together into a SmallVec with a different /// // amount of inline storage, but which is still less than `cap`. - /// let rebuilt = SmallVec::<[_; 2]>::from_raw_parts(p, len, cap); + /// let rebuilt: SmallVec<[_; 2]> = SmallVec::from_raw_parts(p, len, cap); /// assert_eq!(&*rebuilt, &[4, 5, 6]); /// } /// } @@ -735,7 +735,7 @@ where /// ``` /// use smallvec::SmallVec; /// - /// let v = SmallVec::<[char; 128]>::from_elem('d', 2); + /// let v: SmallVec<[char; 128]> = SmallVec::from_elem('d', 2); /// assert_eq!(v, SmallVec::from_buf(['d', 'd'])); /// ``` pub fn from_elem(elem: $array_item, n: usize) -> Self { @@ -1230,37 +1230,6 @@ impl> io::Write for SmallVec { } } -#[cfg(not(feature = "const_generics"))] -macro_rules! impl_index { - ($index_type: ty, $output_type: ty) => { - impl Index<$index_type> for SmallVec { - type Output = $output_type; - #[inline] - fn index(&self, index: $index_type) -> &$output_type { - &(&**self)[index] - } - } - - impl IndexMut<$index_type> for SmallVec { - #[inline] - fn index_mut(&mut self, index: $index_type) -> &mut $output_type { - &mut (&mut **self)[index] - } - } - }; -} - -#[cfg(not(feature = "const_generics"))] -impl_index!(usize, A::Item); -#[cfg(not(feature = "const_generics"))] -impl_index!(Range, [A::Item]); -#[cfg(not(feature = "const_generics"))] -impl_index!(RangeFrom, [A::Item]); -#[cfg(not(feature = "const_generics"))] -impl_index!(RangeTo, [A::Item]); -#[cfg(not(feature = "const_generics"))] -impl_index!(RangeFull, [A::Item]); - #[cfg(feature = "const_generics")] create_with_parts!(, , [T; N], T, N); #[cfg(not(feature = "const_generics"))] diff --git a/src/small_vec_index_impls.rs b/src/small_vec_index_impls.rs new file mode 100644 index 0000000..bda7b7f --- /dev/null +++ b/src/small_vec_index_impls.rs @@ -0,0 +1,109 @@ +// FIXME: It isn't possible to use constant generics inside a +// macro. See https://github.com/rust-lang/rust/issues/61574 + +#[cfg(feature = "const_generics")] +mod impls { + use crate::SmallVec; + use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}; + + impl Index for SmallVec { + type Output = T; + #[inline] + fn index(&self, index: usize) -> &T { + &(&**self)[index] + } + } + impl IndexMut for SmallVec { + #[inline] + fn index_mut(&mut self, index: usize) -> &mut T { + &mut (&mut **self)[index] + } + } + + impl Index> for SmallVec { + type Output = [T]; + #[inline] + fn index(&self, index: Range) -> &[T] { + &(&**self)[index] + } + } + impl IndexMut> for SmallVec { + #[inline] + fn index_mut(&mut self, index: Range) -> &mut [T] { + &mut (&mut **self)[index] + } + } + + impl Index> for SmallVec { + type Output = [T]; + #[inline] + fn index(&self, index: RangeFrom) -> &[T] { + &(&**self)[index] + } + } + impl IndexMut> for SmallVec { + #[inline] + fn index_mut(&mut self, index: RangeFrom) -> &mut [T] { + &mut (&mut **self)[index] + } + } + + impl Index> for SmallVec { + type Output = [T]; + #[inline] + fn index(&self, index: RangeTo) -> &[T] { + &(&**self)[index] + } + } + impl IndexMut> for SmallVec { + #[inline] + fn index_mut(&mut self, index: RangeTo) -> &mut [T] { + &mut (&mut **self)[index] + } + } + + impl Index for SmallVec { + type Output = [T]; + #[inline] + fn index(&self, index: RangeFull) -> &[T] { + &(&**self)[index] + } + } + impl IndexMut for SmallVec { + #[inline] + fn index_mut(&mut self, index: RangeFull) -> &mut [T] { + &mut (&mut **self)[index] + } + } +} + +#[cfg(not(feature = "const_generics"))] +mod impls { + use crate::{Array, SmallVec}; + use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}; + + macro_rules! impl_index { + ($index_type: ty, $output_type: ty) => { + impl Index<$index_type> for SmallVec { + type Output = $output_type; + #[inline] + fn index(&self, index: $index_type) -> &$output_type { + &(&**self)[index] + } + } + + impl IndexMut<$index_type> for SmallVec { + #[inline] + fn index_mut(&mut self, index: $index_type) -> &mut $output_type { + &mut (&mut **self)[index] + } + } + }; + } + + impl_index!(usize, A::Item); + impl_index!(Range, [A::Item]); + impl_index!(RangeFrom, [A::Item]); + impl_index!(RangeTo, [A::Item]); + impl_index!(RangeFull, [A::Item]); +} diff --git a/src/tests.rs b/src/tests.rs index 851fcb4..d9d1967 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -2,9 +2,24 @@ use crate::SmallVec; use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, vec, vec::Vec}; use core::iter::FromIterator; +macro_rules! create_smallvec { + (let $var_name:ident: SmallVec($data_ty:ty, $data_value:expr) = $smallvec:expr) => { + #[cfg(feature = "const_generics")] + let $var_name: SmallVec<$data_ty, $data_value> = $smallvec; + #[cfg(not(feature = "const_generics"))] + let $var_name: SmallVec<[$data_ty; $data_value]> = $smallvec; + }; + (let mut $var_name:ident: SmallVec($data_ty:ty, $data_value:expr) = $smallvec:expr) => { + #[cfg(feature = "const_generics")] + let mut $var_name: SmallVec<$data_ty, $data_value> = $smallvec; + #[cfg(not(feature = "const_generics"))] + let mut $var_name: SmallVec<[$data_ty; $data_value]> = $smallvec; + }; +} + #[test] pub fn test_zero() { - let mut v = SmallVec::<[_; 0]>::new(); + create_smallvec!(let mut v: SmallVec(_, 0) = SmallVec::new()); assert!(!v.spilled()); v.push(0usize); assert!(v.spilled()); @@ -15,7 +30,7 @@ pub fn test_zero() { #[test] pub fn test_inline() { - let mut v = SmallVec::<[_; 16]>::new(); + create_smallvec!(let mut v: SmallVec(_, 16) = SmallVec::new()); v.push("hello".to_owned()); v.push("there".to_owned()); assert_eq!(&*v, &["hello".to_owned(), "there".to_owned()][..]); @@ -23,7 +38,7 @@ pub fn test_inline() { #[test] pub fn test_spill() { - let mut v = SmallVec::<[_; 2]>::new(); + create_smallvec!(let mut v: SmallVec(_, 2) = SmallVec::new()); v.push("hello".to_owned()); assert_eq!(v[0], "hello"); v.push("there".to_owned()); @@ -43,7 +58,7 @@ pub fn test_spill() { #[test] pub fn test_double_spill() { - let mut v = SmallVec::<[_; 2]>::new(); + create_smallvec!(let mut v: SmallVec(_, 2) = SmallVec::new()); v.push("hello".to_owned()); v.push("there".to_owned()); v.push("burma".to_owned()); @@ -70,23 +85,24 @@ pub fn test_double_spill() { /// https://github.com/servo/rust-smallvec/issues/4 #[test] fn issue_4() { - SmallVec::<[Box; 2]>::new(); + create_smallvec!(let _v: SmallVec(Box, 2) = SmallVec::new()); } /// https://github.com/servo/rust-smallvec/issues/5 #[test] fn issue_5() { - assert!(Some(SmallVec::<[&u32; 2]>::new()).is_some()); + create_smallvec!(let v: SmallVec(&u32, 2) = SmallVec::new()); + assert!(Some(v).is_some()); } #[test] fn test_with_capacity() { - let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(1); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::with_capacity(1)); assert!(v.is_empty()); assert!(!v.spilled()); assert_eq!(v.capacity(), 3); - let v: SmallVec<[u8; 3]> = SmallVec::with_capacity(10); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::with_capacity(10)); assert!(v.is_empty()); assert!(v.spilled()); assert_eq!(v.capacity(), 10); @@ -94,7 +110,7 @@ fn test_with_capacity() { #[test] fn drain() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); assert_eq!(v.drain().collect::>(), &[3]); @@ -107,7 +123,7 @@ fn drain() { #[test] fn drain_rev() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); assert_eq!(v.drain().rev().collect::>(), &[3]); @@ -120,12 +136,12 @@ fn drain_rev() { #[test] fn into_iter() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); assert_eq!(v.into_iter().collect::>(), &[3]); // spilling the vec - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); v.push(4); v.push(5); @@ -134,12 +150,12 @@ fn into_iter() { #[test] fn into_iter_rev() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); assert_eq!(v.into_iter().rev().collect::>(), &[3]); // spilling the vec - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(3); v.push(4); v.push(5); @@ -160,7 +176,7 @@ fn into_iter_drop() { { let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(DropCounter, 2) = SmallVec::new()); v.push(DropCounter(&cell)); v.into_iter(); assert_eq!(cell.get(), 1); @@ -168,7 +184,7 @@ fn into_iter_drop() { { let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(DropCounter, 2) = SmallVec::new()); v.push(DropCounter(&cell)); v.push(DropCounter(&cell)); assert!(v.into_iter().next().is_some()); @@ -177,7 +193,7 @@ fn into_iter_drop() { { let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(DropCounter, 2) = SmallVec::new()); v.push(DropCounter(&cell)); v.push(DropCounter(&cell)); v.push(DropCounter(&cell)); @@ -186,7 +202,7 @@ fn into_iter_drop() { } { let cell = Cell::new(0); - let mut v: SmallVec<[DropCounter; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(DropCounter, 2) = SmallVec::new()); v.push(DropCounter(&cell)); v.push(DropCounter(&cell)); v.push(DropCounter(&cell)); @@ -201,7 +217,7 @@ fn into_iter_drop() { #[test] fn test_capacity() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.reserve(1); assert_eq!(v.capacity(), 2); assert!(!v.spilled()); @@ -220,7 +236,7 @@ fn test_capacity() { #[test] fn test_truncate() { - let mut v: SmallVec<[Box; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(Box, 8) = SmallVec::new()); for x in 0..8 { v.push(Box::new(x)); @@ -239,7 +255,7 @@ fn test_truncate() { #[test] fn test_insert_many() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); for x in 0..4 { v.push(x); } @@ -267,7 +283,7 @@ impl Iterator for MockHintIter { #[test] fn test_insert_many_short_hint() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); for x in 0..4 { v.push(x); } @@ -287,7 +303,7 @@ fn test_insert_many_short_hint() { #[test] fn test_insert_many_long_hint() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); for x in 0..4 { v.push(x); } @@ -331,17 +347,16 @@ fn test_insert_many_panic() { } } - let mut vec: SmallVec<[PanicOnDoubleDrop; 0]> = vec![ + create_smallvec!(let mut v: SmallVec(PanicOnDoubleDrop, 0) = vec![ PanicOnDoubleDrop { dropped: Box::new(false), }, PanicOnDoubleDrop { dropped: Box::new(false), }, - ] - .into(); + ].into()); let result = std::panic::catch_unwind(move || { - vec.insert_many(0, BadIter); + v.insert_many(0, BadIter); }); assert!(result.is_err()); } @@ -349,14 +364,14 @@ fn test_insert_many_panic() { #[test] #[should_panic] fn test_invalid_grow() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); v.extend(0..8); v.grow(5); } #[test] fn test_insert_from_slice() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); for x in 0..4 { v.push(x); } @@ -370,7 +385,7 @@ fn test_insert_from_slice() { #[test] fn test_extend_from_slice() { - let mut v: SmallVec<[u8; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 8) = SmallVec::new()); for x in 0..4 { v.push(x); } @@ -395,15 +410,15 @@ fn test_drop_panic_smallvec() { } } - let mut v = SmallVec::<[_; 1]>::new(); + create_smallvec!(let mut v: SmallVec(_, 1) = SmallVec::new()); v.push(DropPanic); } #[test] fn test_eq() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - let mut b: SmallVec<[u32; 2]> = SmallVec::new(); - let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); + create_smallvec!(let mut b: SmallVec(u32, 2) = SmallVec::new()); + create_smallvec!(let mut c: SmallVec(u32, 2) = SmallVec::new()); // a = [1, 2] a.push(1); a.push(2); @@ -420,9 +435,9 @@ fn test_eq() { #[test] fn test_ord() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); - let mut b: SmallVec<[u32; 2]> = SmallVec::new(); - let mut c: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); + create_smallvec!(let mut b: SmallVec(u32, 2) = SmallVec::new()); + create_smallvec!(let mut c: SmallVec(u32, 2) = SmallVec::new()); // a = [1] a.push(1); // b = [1, 1] @@ -444,14 +459,14 @@ fn test_hash() { use std::{collections::hash_map::DefaultHasher, hash::Hash}; { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); let b = [1, 2]; a.extend(b.iter().cloned()); let mut hasher = DefaultHasher::new(); assert_eq!(a.hash(&mut hasher), b.hash(&mut hasher)); } { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); let b = [1, 2, 11, 12]; a.extend(b.iter().cloned()); let mut hasher = DefaultHasher::new(); @@ -461,7 +476,7 @@ fn test_hash() { #[test] fn test_as_ref() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); a.push(1); assert_eq!(a.as_ref(), [1]); a.push(2); @@ -472,7 +487,7 @@ fn test_as_ref() { #[test] fn test_as_mut() { - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); a.push(1); assert_eq!(a.as_mut(), [1]); a.push(2); @@ -487,7 +502,7 @@ fn test_as_mut() { fn test_borrow() { use core::borrow::Borrow; - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); a.push(1); assert_eq!(a.borrow(), [1]); a.push(2); @@ -500,7 +515,7 @@ fn test_borrow() { fn test_borrow_mut() { use core::borrow::BorrowMut; - let mut a: SmallVec<[u32; 2]> = SmallVec::new(); + create_smallvec!(let mut a: SmallVec(u32, 2) = SmallVec::new()); a.push(1); assert_eq!(a.borrow_mut(), [1]); a.push(2); @@ -513,171 +528,173 @@ fn test_borrow_mut() { #[test] fn test_from() { - assert_eq!(&SmallVec::<[u32; 2]>::from(&[1][..])[..], [1]); - assert_eq!(&SmallVec::<[u32; 2]>::from(&[1, 2, 3][..])[..], [1, 2, 3]); + create_smallvec!(let a: SmallVec(u32, 2) = SmallVec::from_slice(&[1][..])); + create_smallvec!(let b: SmallVec(u32, 2) = SmallVec::from_slice(&[1, 2, 3][..])); + assert_eq!(&a[..], [1]); + assert_eq!(&b[..], [1, 2, 3]); let vec = vec![]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from(vec)); + assert_eq!(&*v, &[]); + drop(v); let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from(vec)); + assert_eq!(&*v, &[1, 2, 3, 4, 5]); + drop(v); let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 1) = SmallVec::from(vec)); + assert_eq!(&*v, &[1, 2, 3, 4, 5]); + drop(v); let array = [1]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from(array); - assert_eq!(&*small_vec, &[1]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 1) = SmallVec::from(array)); + assert_eq!(&*v, &[1]); + drop(v); let array = [99; 128]; - let small_vec: SmallVec<[u8; 128]> = SmallVec::from(array); - assert_eq!(&*small_vec, vec![99u8; 128].as_slice()); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 128) = SmallVec::from(array)); + assert_eq!(&*v, vec![99u8; 128].as_slice()); + drop(v); } #[test] fn test_from_slice() { - assert_eq!(&SmallVec::<[u32; 2]>::from_slice(&[1][..])[..], [1]); - assert_eq!( - &SmallVec::<[u32; 2]>::from_slice(&[1, 2, 3][..])[..], - [1, 2, 3] - ); + create_smallvec!(let a: SmallVec(u32, 2) = SmallVec::from_slice(&[1][..])); + create_smallvec!(let b: SmallVec(u32, 2) = SmallVec::from_slice(&[1, 2, 3][..])); + + assert_eq!(&a[..], [1]); + assert_eq!(&b[..], [1, 2, 3]); } #[test] fn test_exact_size_iterator() { - let mut vec = SmallVec::<[u32; 2]>::from(&[1, 2, 3][..]); - assert_eq!(vec.clone().into_iter().len(), 3); - assert_eq!(vec.drain().len(), 3); + create_smallvec!(let mut v: SmallVec(u32, 2) = SmallVec::from(&[1, 2, 3][..])); + assert_eq!(v.clone().into_iter().len(), 3); + assert_eq!(v.drain().len(), 3); } #[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"); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::from_iter(0..3)); + v.pop(); + assert!(v.spilled()); + v.shrink_to_fit(); + assert!(!v.spilled(), "shrink_to_fit will un-spill if possible"); } #[test] fn test_into_vec() { - let vec = SmallVec::<[u8; 2]>::from_iter(0..2); - assert_eq!(vec.into_vec(), vec![0, 1]); + create_smallvec!(let v: SmallVec(u8, 2) = SmallVec::from_iter(0..2)); + assert_eq!(v.into_vec(), vec![0, 1]); - let vec = SmallVec::<[u8; 2]>::from_iter(0..3); - assert_eq!(vec.into_vec(), vec![0, 1, 2]); + create_smallvec!(let v: SmallVec(u8, 2) = SmallVec::from_iter(0..3)); + assert_eq!(v.into_vec(), vec![0, 1, 2]); } #[test] fn test_into_inner() { - let vec = SmallVec::<[u8; 2]>::from_iter(0..2); - assert_eq!(vec.into_inner(), Ok([0, 1])); + create_smallvec!(let v: SmallVec(u8, 2) = SmallVec::from_iter(0..2)); + assert_eq!(v.into_inner(), Ok([0, 1])); - let vec = SmallVec::<[u8; 2]>::from_iter(0..1); - assert_eq!(vec.clone().into_inner(), Err(vec)); + create_smallvec!(let v: SmallVec(u8, 2) = SmallVec::from_iter(0..1)); + assert_eq!(v.clone().into_inner(), Err(v)); - let vec = SmallVec::<[u8; 2]>::from_iter(0..3); - assert_eq!(vec.clone().into_inner(), Err(vec)); + create_smallvec!(let v: SmallVec(u8, 2) = SmallVec::from_iter(0..3)); + assert_eq!(v.clone().into_inner(), Err(v)); } #[test] fn test_from_vec() { let vec = vec![]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[]); + drop(v); let vec = vec![]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 1) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[]); + drop(v); let vec = vec![1]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[1]); + drop(v); let vec = vec![1, 2, 3]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[1, 2, 3]); + drop(v); let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 3]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 3) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[1, 2, 3, 4, 5]); + drop(v); let vec = vec![1, 2, 3, 4, 5]; - let small_vec: SmallVec<[u8; 1]> = SmallVec::from_vec(vec); - assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]); - drop(small_vec); + create_smallvec!(let v: SmallVec(u8, 1) = SmallVec::from_vec(vec)); + assert_eq!(&*v, &[1, 2, 3, 4, 5]); + drop(v); } #[test] fn test_retain() { // Test inline data storate - let mut sv: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); - sv.retain(|&mut i| i != 3); - assert_eq!(sv.pop(), Some(4)); - assert_eq!(sv.pop(), Some(2)); - assert_eq!(sv.pop(), Some(1)); - assert_eq!(sv.pop(), None); + create_smallvec!(let mut v: SmallVec(i32, 5) = SmallVec::from_slice(&[1, 2, 3, 3, 4])); + v.retain(|&mut i| i != 3); + assert_eq!(v.pop(), Some(4)); + assert_eq!(v.pop(), Some(2)); + assert_eq!(v.pop(), Some(1)); + assert_eq!(v.pop(), None); // Test spilled data storage - let mut sv: SmallVec<[i32; 3]> = SmallVec::from_slice(&[1, 2, 3, 3, 4]); - sv.retain(|&mut i| i != 3); - assert_eq!(sv.pop(), Some(4)); - assert_eq!(sv.pop(), Some(2)); - assert_eq!(sv.pop(), Some(1)); - assert_eq!(sv.pop(), None); + create_smallvec!(let mut v: SmallVec(i32, 3) = SmallVec::from_slice(&[1, 2, 3, 3, 4])); + v.retain(|&mut i| i != 3); + assert_eq!(v.pop(), Some(4)); + assert_eq!(v.pop(), Some(2)); + assert_eq!(v.pop(), Some(1)); + assert_eq!(v.pop(), None); // Test that drop implementations are called for inline. let one = Rc::new(1); - let mut sv: SmallVec<[Rc; 3]> = SmallVec::new(); - sv.push(Rc::clone(&one)); + create_smallvec!(let mut v: SmallVec(Rc, 3) = SmallVec::new()); + v.push(Rc::clone(&one)); assert_eq!(Rc::strong_count(&one), 2); - sv.retain(|_| false); + v.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); // Test that drop implementations are called for spilled data. - let mut sv: SmallVec<[Rc; 1]> = SmallVec::new(); - sv.push(Rc::clone(&one)); - sv.push(Rc::new(2)); + create_smallvec!(let mut v: SmallVec(Rc, 1) = SmallVec::new()); + v.push(Rc::clone(&one)); + v.push(Rc::new(2)); assert_eq!(Rc::strong_count(&one), 2); - sv.retain(|_| false); + v.retain(|_| false); assert_eq!(Rc::strong_count(&one), 1); } #[test] fn test_dedup() { - let mut dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 2, 3, 3]); + create_smallvec!(let mut dupes: SmallVec(i32, 5) = SmallVec::from_slice(&[1, 1, 2, 3, 3])); dupes.dedup(); assert_eq!(&*dupes, &[1, 2, 3]); - let mut empty: SmallVec<[i32; 5]> = SmallVec::new(); + create_smallvec!(let mut empty: SmallVec(i32, 5) = SmallVec::new()); empty.dedup(); assert!(empty.is_empty()); - let mut all_ones: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 1, 1, 1, 1]); + create_smallvec!(let mut all_ones: SmallVec(i32, 5) = SmallVec::from_slice(&[1, 1, 1, 1, 1])); all_ones.dedup(); assert_eq!(all_ones.len(), 1); - let mut no_dupes: SmallVec<[i32; 5]> = SmallVec::from_slice(&[1, 2, 3, 4, 5]); + create_smallvec!(let mut no_dupes: SmallVec(i32, 5) = SmallVec::from_slice(&[1, 2, 3, 4, 5])); no_dupes.dedup(); assert_eq!(no_dupes.len(), 5); } #[test] fn test_resize() { - let mut v: SmallVec<[i32; 8]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(i32, 8) = SmallVec::new()); v.push(1); v.resize(5, 0); assert_eq!(v[..], [1, 0, 0, 0, 0][..]); @@ -693,14 +710,14 @@ fn test_write() { let data = [1, 2, 3, 4, 5]; - let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); - let len = small_vec.write(&data[..]).unwrap(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); + let len = v.write(&data[..]).unwrap(); assert_eq!(len, 5); - assert_eq!(small_vec.as_ref(), data.as_ref()); + assert_eq!(v.as_ref(), data.as_ref()); - let mut small_vec: SmallVec<[u8; 2]> = SmallVec::new(); - small_vec.write_all(&data[..]).unwrap(); - assert_eq!(small_vec.as_ref(), data.as_ref()); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); + v.write_all(&data[..]).unwrap(); + assert_eq!(v.as_ref(), data.as_ref()); } #[cfg(feature = "serde")] @@ -710,24 +727,25 @@ extern crate bincode; #[test] fn test_serde() { use self::bincode::{config, deserialize}; - let mut small_vec: SmallVec<[i32; 2]> = SmallVec::new(); - small_vec.push(1); - let encoded = config().limit(100).serialize(&small_vec).unwrap(); - let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); - assert_eq!(small_vec, decoded); - small_vec.push(2); + create_smallvec!(let mut v: SmallVec(i32, 2) = SmallVec::new()); + v.push(1); + let encoded = config().limit(100).serialize(&v).unwrap(); + create_smallvec!(let decoded: SmallVec(i32, 2) = deserialize(&encoded).unwrap()); + assert_eq!(v, decoded); + v.push(2); // Spill the vec - small_vec.push(3); - small_vec.push(4); + v.push(3); + v.push(4); // Check again after spilling. - let encoded = config().limit(100).serialize(&small_vec).unwrap(); - let decoded: SmallVec<[i32; 2]> = deserialize(&encoded).unwrap(); - assert_eq!(small_vec, decoded); + let encoded = config().limit(100).serialize(&v).unwrap(); + + create_smallvec!(let decoded: SmallVec(i32, 2) = deserialize(&encoded).unwrap()); + assert_eq!(v, decoded); } #[test] fn grow_to_shrink() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(1); v.push(2); v.push(3); @@ -749,14 +767,14 @@ fn resumable_extend() { let it = s .chars() .scan(0, |_, ch| if ch.is_whitespace() { None } else { Some(ch) }); - let mut v: SmallVec<[char; 4]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(char, 4) = SmallVec::new()); v.extend(it); assert_eq!(v[..], ['a']); } #[test] fn grow_spilled_same_size() { - let mut v: SmallVec<[u8; 2]> = SmallVec::new(); + create_smallvec!(let mut v: SmallVec(u8, 2) = SmallVec::new()); v.push(0); v.push(1); v.push(2); From 9fed114c43e7db5531c8846f12ec5bbed0e0478b Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 31 Jul 2019 08:56:20 -0300 Subject: [PATCH 23/24] Macro hygiene for constant generics has been fixed --- src/lib.rs | 1 - src/small_vec.rs | 31 +++++++++- src/small_vec_index_impls.rs | 109 ----------------------------------- 3 files changed, 30 insertions(+), 111 deletions(-) delete mode 100644 src/small_vec_index_impls.rs diff --git a/src/lib.rs b/src/lib.rs index 9e40548..bf20354 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,6 @@ mod macros; mod set_len_on_drop; mod small_vec; mod small_vec_data; -mod small_vec_index_impls; #[cfg(feature = "serde")] mod small_vec_visitor; #[cfg(feature = "specialization")] diff --git a/src/small_vec.rs b/src/small_vec.rs index 8ba9e6b..42cc724 100644 --- a/src/small_vec.rs +++ b/src/small_vec.rs @@ -15,7 +15,7 @@ use core::{ hint::unreachable_unchecked, iter::{repeat, FromIterator}, mem::{self, MaybeUninit}, - ops::{Deref, DerefMut}, + ops::{Deref, DerefMut, Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}, ptr, slice, }; #[cfg(feature = "std")] @@ -1161,6 +1161,35 @@ where } } +macro_rules! impl_index { + ($index_type: ty, $output_type: ty) => { + impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> Index<$index_type> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> + { + type Output = $output_type; + #[inline] + fn index(&self, index: $index_type) -> &$output_type { + &(&**self)[index] + } + } + + impl<$($($s_impl_ty_prefix)? $s_impl_ty$(: $s_impl_ty_bound)?),*> IndexMut<$index_type> + for SmallVec<$s_decl_ty$(, {$s_decl_const_ty})?> + { + #[inline] + fn index_mut(&mut self, index: $index_type) -> &mut $output_type { + &mut (&mut **self)[index] + } + } + }; +} + +impl_index!(usize, $array_item); +impl_index!(Range, [$array_item]); +impl_index!(RangeFrom, [$array_item]); +impl_index!(RangeTo, [$array_item]); +impl_index!(RangeFull, [$array_item]); + } } diff --git a/src/small_vec_index_impls.rs b/src/small_vec_index_impls.rs deleted file mode 100644 index bda7b7f..0000000 --- a/src/small_vec_index_impls.rs +++ /dev/null @@ -1,109 +0,0 @@ -// FIXME: It isn't possible to use constant generics inside a -// macro. See https://github.com/rust-lang/rust/issues/61574 - -#[cfg(feature = "const_generics")] -mod impls { - use crate::SmallVec; - use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}; - - impl Index for SmallVec { - type Output = T; - #[inline] - fn index(&self, index: usize) -> &T { - &(&**self)[index] - } - } - impl IndexMut for SmallVec { - #[inline] - fn index_mut(&mut self, index: usize) -> &mut T { - &mut (&mut **self)[index] - } - } - - impl Index> for SmallVec { - type Output = [T]; - #[inline] - fn index(&self, index: Range) -> &[T] { - &(&**self)[index] - } - } - impl IndexMut> for SmallVec { - #[inline] - fn index_mut(&mut self, index: Range) -> &mut [T] { - &mut (&mut **self)[index] - } - } - - impl Index> for SmallVec { - type Output = [T]; - #[inline] - fn index(&self, index: RangeFrom) -> &[T] { - &(&**self)[index] - } - } - impl IndexMut> for SmallVec { - #[inline] - fn index_mut(&mut self, index: RangeFrom) -> &mut [T] { - &mut (&mut **self)[index] - } - } - - impl Index> for SmallVec { - type Output = [T]; - #[inline] - fn index(&self, index: RangeTo) -> &[T] { - &(&**self)[index] - } - } - impl IndexMut> for SmallVec { - #[inline] - fn index_mut(&mut self, index: RangeTo) -> &mut [T] { - &mut (&mut **self)[index] - } - } - - impl Index for SmallVec { - type Output = [T]; - #[inline] - fn index(&self, index: RangeFull) -> &[T] { - &(&**self)[index] - } - } - impl IndexMut for SmallVec { - #[inline] - fn index_mut(&mut self, index: RangeFull) -> &mut [T] { - &mut (&mut **self)[index] - } - } -} - -#[cfg(not(feature = "const_generics"))] -mod impls { - use crate::{Array, SmallVec}; - use core::ops::{Index, IndexMut, Range, RangeFrom, RangeFull, RangeTo}; - - macro_rules! impl_index { - ($index_type: ty, $output_type: ty) => { - impl Index<$index_type> for SmallVec { - type Output = $output_type; - #[inline] - fn index(&self, index: $index_type) -> &$output_type { - &(&**self)[index] - } - } - - impl IndexMut<$index_type> for SmallVec { - #[inline] - fn index_mut(&mut self, index: $index_type) -> &mut $output_type { - &mut (&mut **self)[index] - } - } - }; - } - - impl_index!(usize, A::Item); - impl_index!(Range, [A::Item]); - impl_index!(RangeFrom, [A::Item]); - impl_index!(RangeTo, [A::Item]); - impl_index!(RangeFull, [A::Item]); -} From a61da167ae723432dea263750123dcdbb637aa3b Mon Sep 17 00:00:00 2001 From: Caio Date: Wed, 31 Jul 2019 09:00:23 -0300 Subject: [PATCH 24/24] Allow failures in nightly --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index b90e11c..aeec623 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,6 @@ language: rust +allow_failures: + - rust: nightly rust: - 1.36.0 - beta