Skip to content

Commit a83ccec

Browse files
author
Thom Chiovoloni
committed
Use MaybeUninit for storage of inline items.
This includes two breaking changes, in addition to the fact that it will require a MSRV bump: 1. The functions on the `Array` trait `ptr` and `ptr_mut` have been removed. Because these took a `&self`/`&mut self` argument, there's no way for us to call them when we only have a `MaybeUninit<A>`. Now, we just use the memory of the object directly. This limits the flexibility of custom implementations of `Array`, (they can no longer return pointers to values other than themselves) but I imagine this is very rare and was probably broken somehow to begin with. Anybody who does this will get a compile error. 2. `from_buf_and_len_unchecked` now takes a MaybeUninit<A>, so that callers have the option of only partially initializing the array.
1 parent ae79432 commit a83ccec

File tree

1 file changed

+49
-52
lines changed

1 file changed

+49
-52
lines changed

lib.rs

+49-52
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ use std::iter::{repeat, FromIterator, IntoIterator};
6363
#[cfg(feature = "serde")]
6464
use std::marker::PhantomData;
6565
use std::mem;
66-
use std::mem::ManuallyDrop;
66+
use std::mem::MaybeUninit;
6767
use std::ops;
6868
use std::ptr;
6969
use std::slice;
@@ -280,29 +280,27 @@ impl<'a, T: 'a> Drop for Drain<'a, T> {
280280

281281
#[cfg(feature = "union")]
282282
union SmallVecData<A: Array> {
283-
inline: ManuallyDrop<A>,
283+
inline: MaybeUninit<A>,
284284
heap: (*mut A::Item, usize),
285285
}
286286

287287
#[cfg(feature = "union")]
288288
impl<A: Array> SmallVecData<A> {
289289
#[inline]
290-
unsafe fn inline(&self) -> &A {
291-
&self.inline
290+
unsafe fn inline(&self) -> *const A::Item {
291+
self.inline.as_ptr() as *const A::Item
292292
}
293293
#[inline]
294-
unsafe fn inline_mut(&mut self) -> &mut A {
295-
&mut self.inline
294+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
295+
self.inline.as_mut_ptr() as *mut A::Item
296296
}
297297
#[inline]
298-
fn from_inline(inline: A) -> SmallVecData<A> {
299-
SmallVecData {
300-
inline: ManuallyDrop::new(inline),
301-
}
298+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
299+
SmallVecData { inline }
302300
}
303301
#[inline]
304-
unsafe fn into_inline(self) -> A {
305-
ManuallyDrop::into_inner(self.inline)
302+
unsafe fn into_inline(self) -> MaybeUninit<A> {
303+
self.inline
306304
}
307305
#[inline]
308306
unsafe fn heap(&self) -> (*mut A::Item, usize) {
@@ -320,34 +318,34 @@ impl<A: Array> SmallVecData<A> {
320318

321319
#[cfg(not(feature = "union"))]
322320
enum SmallVecData<A: Array> {
323-
Inline(ManuallyDrop<A>),
321+
Inline(MaybeUninit<A>),
324322
Heap((*mut A::Item, usize)),
325323
}
326324

327325
#[cfg(not(feature = "union"))]
328326
impl<A: Array> SmallVecData<A> {
329327
#[inline]
330-
unsafe fn inline(&self) -> &A {
328+
unsafe fn inline(&self) -> *const A::Item {
331329
match *self {
332-
SmallVecData::Inline(ref a) => a,
330+
SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
333331
_ => debug_unreachable!(),
334332
}
335333
}
336334
#[inline]
337-
unsafe fn inline_mut(&mut self) -> &mut A {
335+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
338336
match *self {
339-
SmallVecData::Inline(ref mut a) => a,
337+
SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
340338
_ => debug_unreachable!(),
341339
}
342340
}
343341
#[inline]
344-
fn from_inline(inline: A) -> SmallVecData<A> {
345-
SmallVecData::Inline(ManuallyDrop::new(inline))
342+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
343+
SmallVecData::Inline(inline)
346344
}
347345
#[inline]
348-
unsafe fn into_inline(self) -> A {
346+
unsafe fn into_inline(self) -> MaybeUninit<A> {
349347
match self {
350-
SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
348+
SmallVecData::Inline(a) => a,
351349
_ => debug_unreachable!(),
352350
}
353351
}
@@ -412,11 +410,15 @@ impl<A: Array> SmallVec<A> {
412410
/// Construct an empty vector
413411
#[inline]
414412
pub fn new() -> SmallVec<A> {
415-
unsafe {
416-
SmallVec {
417-
capacity: 0,
418-
data: SmallVecData::from_inline(mem::uninitialized()),
419-
}
413+
// Try to detect invalid custom implementations of `Array`. Hopefuly,
414+
// this check should be optimized away entirely for valid ones.
415+
assert!(
416+
mem::size_of::<A>() == A::size() * mem::size_of::<A::Item>()
417+
&& mem::align_of::<A>() >= mem::align_of::<A::Item>()
418+
);
419+
SmallVec {
420+
capacity: 0,
421+
data: SmallVecData::from_inline(MaybeUninit::uninit()),
420422
}
421423
}
422424

@@ -456,10 +458,10 @@ impl<A: Array> SmallVec<A> {
456458
pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> {
457459
if vec.capacity() <= A::size() {
458460
unsafe {
459-
let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
461+
let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
460462
let len = vec.len();
461463
vec.set_len(0);
462-
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
464+
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);
463465

464466
SmallVec {
465467
capacity: len,
@@ -492,7 +494,7 @@ impl<A: Array> SmallVec<A> {
492494
pub fn from_buf(buf: A) -> SmallVec<A> {
493495
SmallVec {
494496
capacity: A::size(),
495-
data: SmallVecData::from_inline(buf),
497+
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
496498
}
497499
}
498500

@@ -511,7 +513,7 @@ impl<A: Array> SmallVec<A> {
511513
#[inline]
512514
pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec<A> {
513515
assert!(len <= A::size());
514-
unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) }
516+
unsafe { SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), len) }
515517
}
516518

517519
/// Constructs a new `SmallVec` on the stack from an `A` without
@@ -520,16 +522,17 @@ impl<A: Array> SmallVec<A> {
520522
///
521523
/// ```rust
522524
/// use smallvec::SmallVec;
525+
/// use std::mem::MaybeUninit;
523526
///
524527
/// let buf = [1, 2, 3, 4, 5, 0, 0, 0];
525528
/// let small_vec: SmallVec<_> = unsafe {
526-
/// SmallVec::from_buf_and_len_unchecked(buf, 5)
529+
/// SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5)
527530
/// };
528531
///
529532
/// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]);
530533
/// ```
531534
#[inline]
532-
pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
535+
pub unsafe fn from_buf_and_len_unchecked(buf: MaybeUninit<A>, len: usize) -> SmallVec<A> {
533536
SmallVec {
534537
capacity: len,
535538
data: SmallVecData::from_inline(buf),
@@ -579,7 +582,7 @@ impl<A: Array> SmallVec<A> {
579582
let (ptr, len) = self.data.heap();
580583
(ptr, len, self.capacity)
581584
} else {
582-
(self.data.inline().ptr(), self.capacity, A::size())
585+
(self.data.inline(), self.capacity, A::size())
583586
}
584587
}
585588
}
@@ -592,11 +595,7 @@ impl<A: Array> SmallVec<A> {
592595
let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
593596
(ptr, len_ptr, self.capacity)
594597
} else {
595-
(
596-
self.data.inline_mut().ptr_mut(),
597-
&mut self.capacity,
598-
A::size(),
599-
)
598+
(self.data.inline_mut(), &mut self.capacity, A::size())
600599
}
601600
}
602601
}
@@ -663,8 +662,8 @@ impl<A: Array> SmallVec<A> {
663662
if unspilled {
664663
return;
665664
}
666-
self.data = SmallVecData::from_inline(mem::uninitialized());
667-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
665+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
666+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
668667
self.capacity = len;
669668
} else if new_cap != cap {
670669
let mut vec = Vec::with_capacity(new_cap);
@@ -730,8 +729,8 @@ impl<A: Array> SmallVec<A> {
730729
if self.inline_size() >= len {
731730
unsafe {
732731
let (ptr, len) = self.data.heap();
733-
self.data = SmallVecData::from_inline(mem::uninitialized());
734-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
732+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
733+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
735734
deallocate(ptr, self.capacity);
736735
self.capacity = len;
737736
}
@@ -900,7 +899,7 @@ impl<A: Array> SmallVec<A> {
900899
unsafe {
901900
let data = ptr::read(&self.data);
902901
mem::forget(self);
903-
Ok(data.into_inline())
902+
Ok(data.into_inline().assume_init())
904903
}
905904
}
906905
}
@@ -1062,8 +1061,12 @@ where
10621061
SmallVec {
10631062
capacity: len,
10641063
data: SmallVecData::from_inline(unsafe {
1065-
let mut data: A = mem::uninitialized();
1066-
ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
1064+
let mut data: MaybeUninit<A> = MaybeUninit::uninit();
1065+
ptr::copy_nonoverlapping(
1066+
slice.as_ptr(),
1067+
data.as_mut_ptr() as *mut A::Item,
1068+
len,
1069+
);
10671070
data
10681071
}),
10691072
}
@@ -1603,10 +1606,6 @@ pub unsafe trait Array {
16031606
type Item;
16041607
/// Returns the number of items the array can hold.
16051608
fn size() -> usize;
1606-
/// Returns a pointer to the first element of the array.
1607-
fn ptr(&self) -> *const Self::Item;
1608-
/// Returns a mutable pointer to the first element of the array.
1609-
fn ptr_mut(&mut self) -> *mut Self::Item;
16101609
}
16111610

16121611
/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
@@ -1650,8 +1649,6 @@ macro_rules! impl_array(
16501649
unsafe impl<T> Array for [T; $size] {
16511650
type Item = T;
16521651
fn size() -> usize { $size }
1653-
fn ptr(&self) -> *const T { self.as_ptr() }
1654-
fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
16551652
}
16561653
)+
16571654
}
@@ -1985,7 +1982,7 @@ mod tests {
19851982
);
19861983
}
19871984

1988-
#[cfg(feature = "std")]
1985+
#[cfg(all(feature = "std", not(miri)))] // Miri currently does not support unwinding
19891986
#[test]
19901987
// https://github.com/servo/rust-smallvec/issues/96
19911988
fn test_insert_many_panic() {

0 commit comments

Comments
 (0)