Skip to content

Commit 03c016c

Browse files
author
bors-servo
authored
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 -->
2 parents d38e743 + 1c254ff commit 03c016c

File tree

2 files changed

+86
-0
lines changed

2 files changed

+86
-0
lines changed

benches/bench.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ fn bench_insert(b: &mut Bencher) {
3838
});
3939
}
4040

41+
#[bench]
42+
fn bench_insert_many(b: &mut Bencher) {
43+
#[inline(never)]
44+
fn insert_many_noinline<I: IntoIterator<Item=u64>>(
45+
vec: &mut SmallVec<[u64; 16]>, index: usize, iterable: I) {
46+
vec.insert_many(index, iterable)
47+
}
48+
49+
b.iter(|| {
50+
let mut vec: SmallVec<[u64; 16]> = SmallVec::new();
51+
insert_many_noinline(&mut vec, 0, 0..100);
52+
insert_many_noinline(&mut vec, 0, 0..100);
53+
vec
54+
});
55+
}
56+
4157
#[bench]
4258
fn bench_extend(b: &mut Bencher) {
4359
b.iter(|| {

lib.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,36 @@ impl<A: Array> SmallVec<A> {
445445
self.set_len(len + 1);
446446
}
447447
}
448+
449+
pub fn insert_many<I: IntoIterator<Item=A::Item>>(&mut self, index: usize, iterable: I) {
450+
let iter = iterable.into_iter();
451+
let (lower_size_bound, _) = iter.size_hint();
452+
assert!(lower_size_bound <= std::isize::MAX as usize); // Ensure offset is indexable
453+
assert!(index + lower_size_bound >= index); // Protect against overflow
454+
self.reserve(lower_size_bound);
455+
456+
unsafe {
457+
let old_len = self.len;
458+
assert!(index <= old_len);
459+
let ptr = self.as_mut_ptr().offset(index as isize);
460+
ptr::copy(ptr, ptr.offset(lower_size_bound as isize), old_len - index);
461+
for (off, element) in iter.enumerate() {
462+
if off < lower_size_bound {
463+
ptr::write(ptr.offset(off as isize), element);
464+
self.len = self.len + 1;
465+
} else {
466+
// Iterator provided more elements than the hint.
467+
assert!(index + off >= index); // Protect against overflow.
468+
self.insert(index + off, element);
469+
}
470+
}
471+
let num_added = self.len - old_len;
472+
if num_added < lower_size_bound {
473+
// Iterator provided fewer elements than the hint
474+
ptr::copy(ptr.offset(lower_size_bound as isize), ptr.offset(num_added as isize), old_len - index);
475+
}
476+
}
477+
}
448478
}
449479

450480
impl<A: Array> ops::Deref for SmallVec<A> {
@@ -990,6 +1020,46 @@ pub mod tests {
9901020
assert_eq!(&v.iter().map(|v| **v).collect::<Vec<_>>(), &[0, 3, 2]);
9911021
}
9921022

1023+
#[test]
1024+
fn test_insert_many() {
1025+
let mut v: SmallVec<[u8; 8]> = SmallVec::new();
1026+
for x in 0..4 {
1027+
v.push(x);
1028+
}
1029+
assert_eq!(v.len(), 4);
1030+
v.insert_many(1, [5, 6].iter().cloned());
1031+
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
1032+
}
1033+
1034+
struct MockHintIter<T: Iterator>{x: T, hint: usize}
1035+
impl<T: Iterator> Iterator for MockHintIter<T> {
1036+
type Item = T::Item;
1037+
fn next(&mut self) -> Option<Self::Item> {self.x.next()}
1038+
fn size_hint(&self) -> (usize, Option<usize>) {(self.hint, None)}
1039+
}
1040+
1041+
#[test]
1042+
fn test_insert_many_short_hint() {
1043+
let mut v: SmallVec<[u8; 8]> = SmallVec::new();
1044+
for x in 0..4 {
1045+
v.push(x);
1046+
}
1047+
assert_eq!(v.len(), 4);
1048+
v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 5});
1049+
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
1050+
}
1051+
1052+
#[test]
1053+
fn test_insert_many_long_hint() {
1054+
let mut v: SmallVec<[u8; 8]> = SmallVec::new();
1055+
for x in 0..4 {
1056+
v.push(x);
1057+
}
1058+
assert_eq!(v.len(), 4);
1059+
v.insert_many(1, MockHintIter{x: [5, 6].iter().cloned(), hint: 1});
1060+
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
1061+
}
1062+
9931063
#[test]
9941064
#[should_panic]
9951065
fn test_invalid_grow() {

0 commit comments

Comments
 (0)