зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1632469 - Use `SmallVec::try_reserve`. r=manishearth
Differential Revision: https://phabricator.services.mozilla.com/D72147
This commit is contained in:
Родитель
a6d76f36fb
Коммит
18c4d446c5
|
@ -86,78 +86,34 @@ fn try_double_vec<T>(vec: &mut Vec<T>) -> Result<(), FailedAllocationError> {
|
|||
impl<T: Array> FallibleVec<T::Item> for SmallVec<T> {
|
||||
#[inline(always)]
|
||||
fn try_push(&mut self, val: T::Item) -> Result<(), FailedAllocationError> {
|
||||
#[cfg(feature = "known_system_malloc")]
|
||||
{
|
||||
if self.capacity() == self.len() {
|
||||
try_double_small_vec(self)?;
|
||||
debug_assert!(self.capacity() > self.len());
|
||||
}
|
||||
if self.capacity() == self.len() {
|
||||
try_grow_small_vec(self)?;
|
||||
debug_assert!(self.capacity() > self.len());
|
||||
}
|
||||
self.push(val);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Double the capacity of |svec|, or fail to do so due to lack of memory.
|
||||
// Returns Ok(()) on success, Err(..) on failure.
|
||||
// Grow the capacity of |svec|, or fail to do so due to lack of memory.
|
||||
#[cfg(feature = "known_system_malloc")]
|
||||
#[inline(never)]
|
||||
#[cold]
|
||||
fn try_double_small_vec<T>(svec: &mut SmallVec<T>) -> Result<(), FailedAllocationError>
|
||||
fn try_grow_small_vec<T>(svec: &mut SmallVec<T>) -> Result<(), FailedAllocationError>
|
||||
where
|
||||
T: Array,
|
||||
{
|
||||
use std::mem;
|
||||
use std::ptr::copy_nonoverlapping;
|
||||
|
||||
let old_ptr = svec.as_mut_ptr();
|
||||
let old_len = svec.len();
|
||||
|
||||
let old_cap: usize = svec.capacity();
|
||||
let new_cap: usize = if old_cap == 0 {
|
||||
4
|
||||
} else {
|
||||
old_cap
|
||||
.checked_mul(2)
|
||||
.ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))?
|
||||
let error = match svec.try_reserve(1) {
|
||||
Ok(..) => return Ok(()),
|
||||
Err(e) => e,
|
||||
};
|
||||
|
||||
// This surely shouldn't fail, if |old_cap| was previously accepted as a
|
||||
// valid value. But err on the side of caution.
|
||||
let old_size_bytes = old_cap
|
||||
.checked_mul(mem::size_of::<T>())
|
||||
.ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))?;
|
||||
|
||||
let new_size_bytes = new_cap
|
||||
.checked_mul(mem::size_of::<T>())
|
||||
.ok_or(FailedAllocationError::new("capacity overflow for SmallVec"))?;
|
||||
|
||||
let new_ptr;
|
||||
if svec.spilled() {
|
||||
// There's an old block to free, and, presumably, old contents to
|
||||
// copy. realloc takes care of both aspects.
|
||||
unsafe {
|
||||
new_ptr = alloc::realloc(old_ptr as *mut u8, new_size_bytes);
|
||||
}
|
||||
} else {
|
||||
// There's no old block to free. There may be old contents to copy.
|
||||
unsafe {
|
||||
new_ptr = alloc::alloc(new_size_bytes, 0);
|
||||
if !new_ptr.is_null() && old_size_bytes > 0 {
|
||||
copy_nonoverlapping(old_ptr as *const u8, new_ptr as *mut u8, old_size_bytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if new_ptr.is_null() {
|
||||
return Err(FailedAllocationError::new(
|
||||
Err(match error {
|
||||
smallvec::CollectionAllocErr::AllocErr { .. } => FailedAllocationError::new(
|
||||
"out of memory when allocating SmallVec",
|
||||
));
|
||||
}
|
||||
|
||||
let new_vec = unsafe { Vec::from_raw_parts(new_ptr as *mut T::Item, old_len, new_cap) };
|
||||
|
||||
let new_svec = SmallVec::from_vec(new_vec);
|
||||
mem::forget(mem::replace(svec, new_svec));
|
||||
Ok(())
|
||||
),
|
||||
smallvec::CollectionAllocErr::CapacityOverflow => FailedAllocationError::new(
|
||||
"capacity overflow for SmallVec",
|
||||
),
|
||||
})
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче