Skip to content

Commit e64afc8

Browse files
Thom Chiovolonimbrubeck
Thom Chiovoloni
authored andcommitted
Use MaybeUninit for storage of inline items.
This is a backport of #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 e64afc8

File tree

2 files changed

+54
-40
lines changed

2 files changed

+54
-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 <simon.sapin@exyr.org>"]
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

+52-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

@@ -523,7 +532,7 @@ impl<A: Array> SmallVec<A> {
523532
pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
524533
SmallVec {
525534
capacity: len,
526-
data: SmallVecData::from_inline(buf),
535+
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
527536
}
528537
}
529538

@@ -571,7 +580,7 @@ impl<A: Array> SmallVec<A> {
571580
let (ptr, len) = self.data.heap();
572581
(ptr, len, self.capacity)
573582
} else {
574-
(self.data.inline().ptr(), self.capacity, A::size())
583+
(self.data.inline(), self.capacity, A::size())
575584
}
576585
}
577586
}
@@ -584,7 +593,7 @@ impl<A: Array> SmallVec<A> {
584593
let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
585594
(ptr, len_ptr, self.capacity)
586595
} else {
587-
(self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
596+
(self.data.inline_mut(), &mut self.capacity, A::size())
588597
}
589598
}
590599
}
@@ -651,8 +660,8 @@ impl<A: Array> SmallVec<A> {
651660
if unspilled {
652661
return;
653662
}
654-
self.data = SmallVecData::from_inline(mem::uninitialized());
655-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
663+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
664+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
656665
self.capacity = len;
657666
} else if new_cap != cap {
658667
let mut vec = Vec::with_capacity(new_cap);
@@ -717,8 +726,8 @@ impl<A: Array> SmallVec<A> {
717726
if self.inline_size() >= len {
718727
unsafe {
719728
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);
729+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
730+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
722731
deallocate(ptr, self.capacity);
723732
self.capacity = len;
724733
}
@@ -883,7 +892,7 @@ impl<A: Array> SmallVec<A> {
883892
unsafe {
884893
let data = ptr::read(&self.data);
885894
mem::forget(self);
886-
Ok(data.into_inline())
895+
Ok(data.into_inline().assume_init())
887896
}
888897
}
889898
}
@@ -1041,8 +1050,12 @@ impl<A: Array> SmallVec<A> where A::Item: Copy {
10411050
SmallVec {
10421051
capacity: len,
10431052
data: SmallVecData::from_inline(unsafe {
1044-
let mut data: A = mem::uninitialized();
1045-
ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
1053+
let mut data: MaybeUninit<A> = MaybeUninit::uninit();
1054+
ptr::copy_nonoverlapping(
1055+
slice.as_ptr(),
1056+
data.as_mut_ptr() as *mut A::Item,
1057+
len,
1058+
);
10461059
data
10471060
})
10481061
}
@@ -1587,8 +1600,8 @@ macro_rules! impl_array(
15871600
unsafe impl<T> Array for [T; $size] {
15881601
type Item = T;
15891602
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() }
1603+
fn ptr(&self) -> *const T { unimplemented!() }
1604+
fn ptr_mut(&mut self) -> *mut T { unimplemented!() }
15921605
}
15931606
)+
15941607
}
@@ -1889,7 +1902,7 @@ mod tests {
18891902
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
18901903
}
18911904

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

0 commit comments

Comments
 (0)