Skip to content

Commit d3980ca

Browse files
Thom Chiovolonimbrubeck
Thom Chiovoloni
authored andcommitted
Use MaybeUninit for storage of inline items.
This is a backport of servo#162 to the smallvec 0.6 branch. To avoid bumping the minimum Rust version, the `maybe-uninit` crate is used in place of `std::mem::MaybeUninit`. To avoid breaking changes, the `Array::ptr` and `ptr_mut` methods are retained but are no longer used, and the API to `from_buf_and_len_unchecked` is unchanged.
1 parent 87f156b commit d3980ca

File tree

2 files changed

+55
-40
lines changed

2 files changed

+55
-40
lines changed

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "smallvec"
3-
version = "0.6.12"
3+
version = "0.6.13"
44
authors = ["Simon Sapin <[email protected]>"]
55
license = "MIT/Apache-2.0"
66
repository = "https://github.com/servo/rust-smallvec"
@@ -23,6 +23,7 @@ path = "lib.rs"
2323

2424
[dependencies]
2525
serde = { version = "1", optional = true }
26+
maybe-uninit = "2.0"
2627

2728
[dev_dependencies]
2829
bincode = "1.0.1"

lib.rs

+53-39
Original file line numberDiff line numberDiff line change
@@ -45,18 +45,21 @@ use alloc::vec::Vec;
4545
#[cfg(feature = "serde")]
4646
extern crate serde;
4747

48+
extern crate maybe_uninit;
49+
4850
#[cfg(not(feature = "std"))]
4951
mod std {
5052
pub use core::*;
5153
}
5254

55+
use maybe_uninit::MaybeUninit;
56+
5357
use std::borrow::{Borrow, BorrowMut};
5458
use std::cmp;
5559
use std::fmt;
5660
use std::hash::{Hash, Hasher};
5761
use std::iter::{IntoIterator, FromIterator, repeat};
5862
use std::mem;
59-
use std::mem::ManuallyDrop;
6063
use std::ops;
6164
use std::ptr;
6265
use std::slice;
@@ -275,26 +278,28 @@ impl<'a, T: 'a> Drop for Drain<'a,T> {
275278

276279
#[cfg(feature = "union")]
277280
union SmallVecData<A: Array> {
278-
inline: ManuallyDrop<A>,
281+
inline: MaybeUninit<A>,
279282
heap: (*mut A::Item, usize),
280283
}
281284

282285
#[cfg(feature = "union")]
283286
impl<A: Array> SmallVecData<A> {
284287
#[inline]
285-
unsafe fn inline(&self) -> &A {
286-
&self.inline
288+
unsafe fn inline(&self) -> *const A::Item {
289+
self.inline.as_ptr() as *const A::Item
287290
}
288291
#[inline]
289-
unsafe fn inline_mut(&mut self) -> &mut A {
290-
&mut self.inline
292+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
293+
self.inline.as_mut_ptr() as *mut A::Item
291294
}
292295
#[inline]
293-
fn from_inline(inline: A) -> SmallVecData<A> {
294-
SmallVecData { inline: ManuallyDrop::new(inline) }
296+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
297+
SmallVecData { inline }
295298
}
296299
#[inline]
297-
unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) }
300+
unsafe fn into_inline(self) -> MaybeUninit<A> {
301+
self.inline
302+
}
298303
#[inline]
299304
unsafe fn heap(&self) -> (*mut A::Item, usize) {
300305
self.heap
@@ -311,34 +316,34 @@ impl<A: Array> SmallVecData<A> {
311316

312317
#[cfg(not(feature = "union"))]
313318
enum SmallVecData<A: Array> {
314-
Inline(ManuallyDrop<A>),
319+
Inline(MaybeUninit<A>),
315320
Heap((*mut A::Item, usize)),
316321
}
317322

318323
#[cfg(not(feature = "union"))]
319324
impl<A: Array> SmallVecData<A> {
320325
#[inline]
321-
unsafe fn inline(&self) -> &A {
326+
unsafe fn inline(&self) -> *const A::Item {
322327
match *self {
323-
SmallVecData::Inline(ref a) => a,
328+
SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
324329
_ => debug_unreachable!(),
325330
}
326331
}
327332
#[inline]
328-
unsafe fn inline_mut(&mut self) -> &mut A {
333+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
329334
match *self {
330-
SmallVecData::Inline(ref mut a) => a,
335+
SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
331336
_ => debug_unreachable!(),
332337
}
333338
}
334339
#[inline]
335-
fn from_inline(inline: A) -> SmallVecData<A> {
336-
SmallVecData::Inline(ManuallyDrop::new(inline))
340+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
341+
SmallVecData::Inline(inline)
337342
}
338343
#[inline]
339-
unsafe fn into_inline(self) -> A {
344+
unsafe fn into_inline(self) -> MaybeUninit<A> {
340345
match self {
341-
SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
346+
SmallVecData::Inline(a) => a,
342347
_ => debug_unreachable!(),
343348
}
344349
}
@@ -403,11 +408,15 @@ impl<A: Array> SmallVec<A> {
403408
/// Construct an empty vector
404409
#[inline]
405410
pub fn new() -> SmallVec<A> {
406-
unsafe {
407-
SmallVec {
408-
capacity: 0,
409-
data: SmallVecData::from_inline(mem::uninitialized()),
410-
}
411+
// Try to detect invalid custom implementations of `Array`. Hopefuly,
412+
// this check should be optimized away entirely for valid ones.
413+
assert!(
414+
mem::size_of::<A>() == A::size() * mem::size_of::<A::Item>()
415+
&& mem::align_of::<A>() >= mem::align_of::<A::Item>()
416+
);
417+
SmallVec {
418+
capacity: 0,
419+
data: SmallVecData::from_inline(MaybeUninit::uninit()),
411420
}
412421
}
413422

@@ -447,10 +456,10 @@ impl<A: Array> SmallVec<A> {
447456
pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> {
448457
if vec.capacity() <= A::size() {
449458
unsafe {
450-
let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
459+
let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
451460
let len = vec.len();
452461
vec.set_len(0);
453-
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
462+
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);
454463

455464
SmallVec {
456465
capacity: len,
@@ -483,7 +492,7 @@ impl<A: Array> SmallVec<A> {
483492
pub fn from_buf(buf: A) -> SmallVec<A> {
484493
SmallVec {
485494
capacity: A::size(),
486-
data: SmallVecData::from_inline(buf),
495+
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
487496
}
488497
}
489498

@@ -511,6 +520,7 @@ impl<A: Array> SmallVec<A> {
511520
///
512521
/// ```rust
513522
/// use smallvec::SmallVec;
523+
/// use std::mem::MaybeUninit;
514524
///
515525
/// let buf = [1, 2, 3, 4, 5, 0, 0, 0];
516526
/// let small_vec: SmallVec<_> = unsafe {
@@ -523,7 +533,7 @@ impl<A: Array> SmallVec<A> {
523533
pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
524534
SmallVec {
525535
capacity: len,
526-
data: SmallVecData::from_inline(buf),
536+
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
527537
}
528538
}
529539

@@ -571,7 +581,7 @@ impl<A: Array> SmallVec<A> {
571581
let (ptr, len) = self.data.heap();
572582
(ptr, len, self.capacity)
573583
} else {
574-
(self.data.inline().ptr(), self.capacity, A::size())
584+
(self.data.inline(), self.capacity, A::size())
575585
}
576586
}
577587
}
@@ -584,7 +594,7 @@ impl<A: Array> SmallVec<A> {
584594
let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
585595
(ptr, len_ptr, self.capacity)
586596
} else {
587-
(self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
597+
(self.data.inline_mut(), &mut self.capacity, A::size())
588598
}
589599
}
590600
}
@@ -651,8 +661,8 @@ impl<A: Array> SmallVec<A> {
651661
if unspilled {
652662
return;
653663
}
654-
self.data = SmallVecData::from_inline(mem::uninitialized());
655-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
664+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
665+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
656666
self.capacity = len;
657667
} else if new_cap != cap {
658668
let mut vec = Vec::with_capacity(new_cap);
@@ -717,8 +727,8 @@ impl<A: Array> SmallVec<A> {
717727
if self.inline_size() >= len {
718728
unsafe {
719729
let (ptr, len) = self.data.heap();
720-
self.data = SmallVecData::from_inline(mem::uninitialized());
721-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
730+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
731+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
722732
deallocate(ptr, self.capacity);
723733
self.capacity = len;
724734
}
@@ -883,7 +893,7 @@ impl<A: Array> SmallVec<A> {
883893
unsafe {
884894
let data = ptr::read(&self.data);
885895
mem::forget(self);
886-
Ok(data.into_inline())
896+
Ok(data.into_inline().assume_init())
887897
}
888898
}
889899
}
@@ -1041,8 +1051,12 @@ impl<A: Array> SmallVec<A> where A::Item: Copy {
10411051
SmallVec {
10421052
capacity: len,
10431053
data: SmallVecData::from_inline(unsafe {
1044-
let mut data: A = mem::uninitialized();
1045-
ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
1054+
let mut data: MaybeUninit<A> = MaybeUninit::uninit();
1055+
ptr::copy_nonoverlapping(
1056+
slice.as_ptr(),
1057+
data.as_mut_ptr() as *mut A::Item,
1058+
len,
1059+
);
10461060
data
10471061
})
10481062
}
@@ -1587,8 +1601,8 @@ macro_rules! impl_array(
15871601
unsafe impl<T> Array for [T; $size] {
15881602
type Item = T;
15891603
fn size() -> usize { $size }
1590-
fn ptr(&self) -> *const T { self.as_ptr() }
1591-
fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
1604+
fn ptr(&self) -> *const T { unimplemented!() }
1605+
fn ptr_mut(&mut self) -> *mut T { unimplemented!() }
15921606
}
15931607
)+
15941608
}
@@ -1889,7 +1903,7 @@ mod tests {
18891903
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
18901904
}
18911905

1892-
#[cfg(feature = "std")]
1906+
#[cfg(all(feature = "std", not(miri)))] // Miri currently does not support unwinding
18931907
#[test]
18941908
// https://github.com/servo/rust-smallvec/issues/96
18951909
fn test_insert_many_panic() {

0 commit comments

Comments
 (0)