Skip to content

Commit

Permalink
Make from_elem panic-safe
Browse files Browse the repository at this point in the history
Fixes #101
  • Loading branch information
mbrubeck committed Jul 18, 2018
1 parent 26b2490 commit 1f40252
Showing 1 changed file with 32 additions and 7 deletions.
39 changes: 32 additions & 7 deletions lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -946,19 +946,17 @@ impl<A: Array> SmallVec<A> where A::Item: Clone {
if n > A::size() {
vec![elem; n].into()
} else {
let mut v = SmallVec::<A>::new();
unsafe {
let mut arr: A = ::std::mem::uninitialized();
let ptr = arr.ptr_mut();
let (ptr, len_ptr, _) = v.triple_mut();
let mut local_len = SetLenOnDrop::new(len_ptr);

for i in 0..n as isize {
::std::ptr::write(ptr.offset(i), elem.clone());
}

SmallVec {
capacity: n,
data: SmallVecData::from_inline(arr),
local_len.increment_len(1);
}
}
v
}
}
}
Expand Down Expand Up @@ -1346,6 +1344,33 @@ pub unsafe trait Array {
fn ptr_mut(&mut self) -> *mut Self::Item;
}

/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
///
/// Copied from https://github.com/rust-lang/rust/pull/36355
struct SetLenOnDrop<'a> {
len: &'a mut usize,
local_len: usize,
}

impl<'a> SetLenOnDrop<'a> {
#[inline]
fn new(len: &'a mut usize) -> Self {
SetLenOnDrop { local_len: *len, len: len }
}

#[inline]
fn increment_len(&mut self, increment: usize) {
self.local_len += increment;
}
}

impl<'a> Drop for SetLenOnDrop<'a> {
#[inline]
fn drop(&mut self) {
*self.len = self.local_len;
}
}

macro_rules! impl_array(
($($size:expr),+) => {
$(
Expand Down

0 comments on commit 1f40252

Please sign in to comment.