mirror of
https://github.com/openharmony/third_party_rust_tinyvec.git
synced 2026-07-18 12:25:35 -04:00
Outline the drain to heap logic in TinyVec::push (#127)
* Outline the drain to heap logic in TinyVec::push * Use #[cold] and explain the outlining in a comment
This commit is contained in:
+25
-9
@@ -676,18 +676,34 @@ impl<A: Array> TinyVec<A> {
|
||||
/// tv.push(4);
|
||||
/// assert_eq!(tv.as_slice(), &[1, 2, 3, 4]);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
#[inline]
|
||||
pub fn push(&mut self, val: A::Item) {
|
||||
let arr = match self {
|
||||
TinyVec::Heap(v) => return v.push(val),
|
||||
TinyVec::Inline(a) => a,
|
||||
};
|
||||
|
||||
if let Some(x) = arr.try_push(val) {
|
||||
// The code path for moving the inline contents to the heap produces a lot
|
||||
// of instructions, but we have a strong guarantee that this is a cold
|
||||
// path. LLVM doesn't know this, inlines it, and this tends to cause a
|
||||
// cascade of other bad inlining decisions because the body of push looks
|
||||
// huge even though nearly every call executes the same few instructions.
|
||||
//
|
||||
// Moving the logic out of line with #[cold] causes the hot code to be
|
||||
// inlined together, and we take the extra cost of a function call only
|
||||
// in rare cases.
|
||||
#[cold]
|
||||
fn drain_to_heap_and_push<A: Array>(
|
||||
arr: &mut ArrayVec<A>, val: A::Item,
|
||||
) -> TinyVec<A> {
|
||||
/* Make the Vec twice the size to amortize the cost of draining */
|
||||
let mut v = arr.drain_to_vec_and_reserve(arr.len());
|
||||
v.push(x);
|
||||
*self = TinyVec::Heap(v);
|
||||
v.push(val);
|
||||
TinyVec::Heap(v)
|
||||
}
|
||||
|
||||
match self {
|
||||
TinyVec::Heap(v) => v.push(val),
|
||||
TinyVec::Inline(arr) => {
|
||||
if let Some(x) = arr.try_push(val) {
|
||||
*self = drain_to_heap_and_push(arr, x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user