mirror of
https://github.com/openharmony/third_party_rust_rust-smallvec.git
synced 2026-07-19 23:03:32 -04:00
Auto merge of #93 - Vurich:extend-opts, r=mbrubeck
Optimize `extend` and `from_elem` This increases the amount of unsafe code, and so should be carefully checked. However, the use of unsafe code is quite benign and depends only on the invariant that `grow` always succeeds (which is depended on other places in the codebase) Benchcmp results: ``` name preopt.bench ns/iter postopt.bench ns/iter diff ns/iter diff % speedup bench_extend 277 89 -188 -67.87% x 3.11 bench_macro_from_elem 214 61 -153 -71.50% x 3.51 ``` I took a crack at this after noticing how awful the generated assembly for `SmallVec::from_elem` is even for really simple types like integers. It's still not great but it at least now for the case of `Copy` types it gets autovectorised. Probably someone could make it even better if they spent more time on it. <!-- 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/93) <!-- Reviewable:end -->
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
#[cfg_attr(test, macro_use)]
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
@@ -637,6 +637,10 @@ impl<A: Array> SmallVec<A> {
|
||||
/// back.
|
||||
pub fn insert_many<I: IntoIterator<Item=A::Item>>(&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 <= std::isize::MAX as usize); // Ensure offset is indexable
|
||||
assert!(index + lower_size_bound >= index); // Protect against overflow
|
||||
@@ -805,9 +809,23 @@ impl<A: Array> SmallVec<A> where A::Item: Clone {
|
||||
/// assert_eq!(v, SmallVec::from_buf(['d', 'd']));
|
||||
/// ```
|
||||
pub fn from_elem(elem: A::Item, n: usize) -> Self {
|
||||
let mut v = SmallVec::with_capacity(n);
|
||||
v.insert_many(0, (0..n).map(|_| elem.clone()));
|
||||
v
|
||||
if n > A::size() {
|
||||
vec![elem; n].into()
|
||||
} else {
|
||||
unsafe {
|
||||
let mut arr: A = ::std::mem::uninitialized();
|
||||
let ptr = arr.ptr_mut();
|
||||
|
||||
for i in 0..n as isize {
|
||||
::std::ptr::write(ptr.offset(i), elem.clone());
|
||||
}
|
||||
|
||||
SmallVec {
|
||||
data: Inline { array: arr },
|
||||
len: n,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1001,13 +1019,30 @@ impl<A: Array> FromIterator<A::Item> for SmallVec<A> {
|
||||
|
||||
impl<A: Array> Extend<A::Item> for SmallVec<A> {
|
||||
fn extend<I: IntoIterator<Item=A::Item>>(&mut self, iterable: I) {
|
||||
let iter = iterable.into_iter();
|
||||
let mut iter = iterable.into_iter();
|
||||
let (lower_size_bound, _) = iter.size_hint();
|
||||
|
||||
let target_len = self.len + lower_size_bound;
|
||||
|
||||
if target_len > self.capacity() {
|
||||
self.grow(target_len);
|
||||
self.grow(target_len);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let ptr = self.as_mut_ptr().offset(self.len() as isize);
|
||||
|
||||
let len = self.len();
|
||||
let mut count = 0;
|
||||
for p in 0..lower_size_bound as isize {
|
||||
if let Some(out) = iter.next() {
|
||||
::std::ptr::write(ptr.offset(p), out);
|
||||
count += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
self.set_len(len + count);
|
||||
}
|
||||
|
||||
for elem in iter {
|
||||
|
||||
Reference in New Issue
Block a user