Skip to content

Commit af74e08

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 3ee6d1e commit af74e08

File tree

1 file changed

+44
-45
lines changed

1 file changed

+44
-45
lines changed

lib.rs

+44-45
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use std::fmt;
5656
use std::hash::{Hash, Hasher};
5757
use std::iter::{IntoIterator, FromIterator, repeat};
5858
use std::mem;
59-
use std::mem::ManuallyDrop;
59+
use std::mem::MaybeUninit;
6060
use std::ops;
6161
use std::ptr;
6262
use std::slice;
@@ -275,26 +275,26 @@ impl<'a, T: 'a> Drop for Drain<'a,T> {
275275

276276
#[cfg(feature = "union")]
277277
union SmallVecData<A: Array> {
278-
inline: ManuallyDrop<A>,
278+
inline: MaybeUninit<A>,
279279
heap: (*mut A::Item, usize),
280280
}
281281

282282
#[cfg(feature = "union")]
283283
impl<A: Array> SmallVecData<A> {
284284
#[inline]
285-
unsafe fn inline(&self) -> &A {
286-
&self.inline
285+
unsafe fn inline(&self) -> *const A::Item {
286+
self.inline.as_ptr() as *const A::Item
287287
}
288288
#[inline]
289-
unsafe fn inline_mut(&mut self) -> &mut A {
290-
&mut self.inline
289+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
290+
self.inline.as_mut_ptr() as *mut A::Item
291291
}
292292
#[inline]
293-
fn from_inline(inline: A) -> SmallVecData<A> {
294-
SmallVecData { inline: ManuallyDrop::new(inline) }
293+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
294+
SmallVecData { inline }
295295
}
296296
#[inline]
297-
unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) }
297+
unsafe fn into_inline(self) -> MaybeUninit<A> { self.inline }
298298
#[inline]
299299
unsafe fn heap(&self) -> (*mut A::Item, usize) {
300300
self.heap
@@ -311,34 +311,34 @@ impl<A: Array> SmallVecData<A> {
311311

312312
#[cfg(not(feature = "union"))]
313313
enum SmallVecData<A: Array> {
314-
Inline(ManuallyDrop<A>),
314+
Inline(MaybeUninit<A>),
315315
Heap((*mut A::Item, usize)),
316316
}
317317

318318
#[cfg(not(feature = "union"))]
319319
impl<A: Array> SmallVecData<A> {
320320
#[inline]
321-
unsafe fn inline(&self) -> &A {
321+
unsafe fn inline(&self) -> *const A::Item {
322322
match *self {
323-
SmallVecData::Inline(ref a) => a,
323+
SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
324324
_ => debug_unreachable!(),
325325
}
326326
}
327327
#[inline]
328-
unsafe fn inline_mut(&mut self) -> &mut A {
328+
unsafe fn inline_mut(&mut self) -> *mut A::Item {
329329
match *self {
330-
SmallVecData::Inline(ref mut a) => a,
330+
SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
331331
_ => debug_unreachable!(),
332332
}
333333
}
334334
#[inline]
335-
fn from_inline(inline: A) -> SmallVecData<A> {
336-
SmallVecData::Inline(ManuallyDrop::new(inline))
335+
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
336+
SmallVecData::Inline(inline)
337337
}
338338
#[inline]
339-
unsafe fn into_inline(self) -> A {
339+
unsafe fn into_inline(self) -> MaybeUninit<A> {
340340
match self {
341-
SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
341+
SmallVecData::Inline(a) => a,
342342
_ => debug_unreachable!(),
343343
}
344344
}
@@ -403,11 +403,15 @@ impl<A: Array> SmallVec<A> {
403403
/// Construct an empty vector
404404
#[inline]
405405
pub fn new() -> SmallVec<A> {
406-
unsafe {
407-
SmallVec {
408-
capacity: 0,
409-
data: SmallVecData::from_inline(mem::uninitialized()),
410-
}
406+
// Try to detect invalid custom implementations of `Array`. Hopefuly,
407+
// this check should be optimized away entirely for valid ones.
408+
assert!(
409+
(mem::size_of::<A>() == A::size() * mem::size_of::<A::Item>()) &&
410+
(mem::align_of::<A>() >= mem::align_of::<A::Item>())
411+
);
412+
SmallVec {
413+
capacity: 0,
414+
data: SmallVecData::from_inline(MaybeUninit::uninit()),
411415
}
412416
}
413417

@@ -447,10 +451,10 @@ impl<A: Array> SmallVec<A> {
447451
pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> {
448452
if vec.capacity() <= A::size() {
449453
unsafe {
450-
let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
454+
let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
451455
let len = vec.len();
452456
vec.set_len(0);
453-
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
457+
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);
454458

455459
SmallVec {
456460
capacity: len,
@@ -483,7 +487,7 @@ impl<A: Array> SmallVec<A> {
483487
pub fn from_buf(buf: A) -> SmallVec<A> {
484488
SmallVec {
485489
capacity: A::size(),
486-
data: SmallVecData::from_inline(buf),
490+
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
487491
}
488492
}
489493

@@ -502,7 +506,7 @@ impl<A: Array> SmallVec<A> {
502506
#[inline]
503507
pub fn from_buf_and_len(buf: A, len: usize) -> SmallVec<A> {
504508
assert!(len <= A::size());
505-
unsafe { SmallVec::from_buf_and_len_unchecked(buf, len) }
509+
unsafe { SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), len) }
506510
}
507511

508512
/// Constructs a new `SmallVec` on the stack from an `A` without
@@ -511,16 +515,17 @@ impl<A: Array> SmallVec<A> {
511515
///
512516
/// ```rust
513517
/// use smallvec::SmallVec;
518+
/// use std::mem::MaybeUninit;
514519
///
515520
/// let buf = [1, 2, 3, 4, 5, 0, 0, 0];
516521
/// let small_vec: SmallVec<_> = unsafe {
517-
/// SmallVec::from_buf_and_len_unchecked(buf, 5)
522+
/// SmallVec::from_buf_and_len_unchecked(MaybeUninit::new(buf), 5)
518523
/// };
519524
///
520525
/// assert_eq!(&*small_vec, &[1, 2, 3, 4, 5]);
521526
/// ```
522527
#[inline]
523-
pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
528+
pub unsafe fn from_buf_and_len_unchecked(buf: MaybeUninit<A>, len: usize) -> SmallVec<A> {
524529
SmallVec {
525530
capacity: len,
526531
data: SmallVecData::from_inline(buf),
@@ -571,7 +576,7 @@ impl<A: Array> SmallVec<A> {
571576
let (ptr, len) = self.data.heap();
572577
(ptr, len, self.capacity)
573578
} else {
574-
(self.data.inline().ptr(), self.capacity, A::size())
579+
(self.data.inline(), self.capacity, A::size())
575580
}
576581
}
577582
}
@@ -584,7 +589,7 @@ impl<A: Array> SmallVec<A> {
584589
let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
585590
(ptr, len_ptr, self.capacity)
586591
} else {
587-
(self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
592+
(self.data.inline_mut(), &mut self.capacity, A::size())
588593
}
589594
}
590595
}
@@ -651,8 +656,8 @@ impl<A: Array> SmallVec<A> {
651656
if unspilled {
652657
return;
653658
}
654-
self.data = SmallVecData::from_inline(mem::uninitialized());
655-
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
659+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
660+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
656661
self.capacity = len;
657662
} else if new_cap != cap {
658663
let mut vec = Vec::with_capacity(new_cap);
@@ -717,8 +722,8 @@ impl<A: Array> SmallVec<A> {
717722
if self.inline_size() >= len {
718723
unsafe {
719724
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);
725+
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
726+
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
722727
deallocate(ptr, self.capacity);
723728
self.capacity = len;
724729
}
@@ -883,7 +888,7 @@ impl<A: Array> SmallVec<A> {
883888
unsafe {
884889
let data = ptr::read(&self.data);
885890
mem::forget(self);
886-
Ok(data.into_inline())
891+
Ok(data.into_inline().assume_init())
887892
}
888893
}
889894
}
@@ -1041,8 +1046,8 @@ impl<A: Array> SmallVec<A> where A::Item: Copy {
10411046
SmallVec {
10421047
capacity: len,
10431048
data: SmallVecData::from_inline(unsafe {
1044-
let mut data: A = mem::uninitialized();
1045-
ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
1049+
let mut data: MaybeUninit<A> = MaybeUninit::uninit();
1050+
ptr::copy_nonoverlapping(slice.as_ptr(), data.as_mut_ptr() as *mut A::Item, len);
10461051
data
10471052
})
10481053
}
@@ -1543,10 +1548,6 @@ pub unsafe trait Array {
15431548
type Item;
15441549
/// Returns the number of items the array can hold.
15451550
fn size() -> usize;
1546-
/// Returns a pointer to the first element of the array.
1547-
fn ptr(&self) -> *const Self::Item;
1548-
/// Returns a mutable pointer to the first element of the array.
1549-
fn ptr_mut(&mut self) -> *mut Self::Item;
15501551
}
15511552

15521553
/// Set the length of the vec when the `SetLenOnDrop` value goes out of scope.
@@ -1587,8 +1588,6 @@ macro_rules! impl_array(
15871588
unsafe impl<T> Array for [T; $size] {
15881589
type Item = T;
15891590
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() }
15921591
}
15931592
)+
15941593
}
@@ -1889,7 +1888,7 @@ mod tests {
18891888
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
18901889
}
18911890

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

0 commit comments

Comments
 (0)