Auto merge of #28 - nipunn1313:insert_slice, r=jdm

Implement insert_many<IntoIterator> for SmallVec

This doesn't work as is, but I wanted to put it up for feedback.

According to these docs:
https://doc.rust-lang.org/std/ptr/fn.copy_nonoverlapping.html

The copy_nonoverlapping function copies memory as intended, but the ownership of the values copied are not copied over to dest, so when the box is consumed, the SmallVec does not maintain ownership. Not sure how to do this with unsafe code.

<!-- Reviewable:start -->

---

This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/rust-smallvec/28)

<!-- Reviewable:end -->
This commit is contained in:
bors-servo
2017-01-19 15:53:05 -08:00
committed by GitHub
2 changed files with 86 additions and 0 deletions
+16
View File
@@ -38,6 +38,22 @@ fn bench_insert(b: &mut Bencher) {
});
}
#[bench]
fn bench_insert_many(b: &mut Bencher) {
#[inline(never)]
fn insert_many_noinline<I: IntoIterator<Item=u64>>(
vec: &mut SmallVec<[u64; 16]>, index: usize, iterable: I) {
vec.insert_many(index, iterable)
}
b.iter(|| {
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
insert_many_noinline(&mut vec, 0, 0..100);
insert_many_noinline(&mut vec, 0, 0..100);
vec
});
}
#[bench]
fn bench_extend(b: &mut Bencher) {
b.iter(|| {
+70
View File
@@ -445,6 +445,36 @@ impl<A: Array> SmallVec<A> {
self.set_len(len + 1);
}
}
pub fn insert_many<I: IntoIterator<Item=A::Item>>(&mut self, index: usize, iterable: I) {
let iter = iterable.into_iter();
let (lower_size_bound, _) = iter.size_hint();
assert!(lower_size_bound <= std::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 ptr = self.as_mut_ptr().offset(index as isize);
ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index);
for (off, element) in iter.enumerate() {
if off < lower_size_bound {
ptr::write(ptr.offset(off as isize), element);
self.len = self.len + 1;
} else {
// Iterator provided more elements than the hint.
assert!(index + off >= index); // Protect against overflow.
self.insert(index + off, element);
}
}
let num_added = self.len - old_len;
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);
}
}
}
}
impl<A: Array> ops::Deref for SmallVec<A> {
@@ -990,6 +1020,46 @@ pub mod tests {
assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[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::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
}
struct MockHintIter<T: Iterator>{x: T, hint: usize}
impl<T: Iterator> Iterator for MockHintIter<T> {
type Item = T::Item;
fn next(&mut self) -> Option<Self::Item> {self.x.next()}
fn size_hint(&self) -> (usize, Option<usize>) {(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::<Vec<_>>(), &[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::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
}
#[test]
#[should_panic]
fn test_invalid_grow() {