Skip to content

Commit

Permalink
Merge pull request #180 from mbrubeck/maybe_uninit
Browse files Browse the repository at this point in the history
Backport MaybeUninit changes to 0.6
  • Loading branch information
emilio committed Nov 5, 2019
2 parents 87f156b + 58d5416 commit 7852204
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 41 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Expand Up @@ -11,4 +11,5 @@ script: |
([ $TRAVIS_RUST_VERSION != nightly ] || cargo check --verbose --no-default-features) &&
([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --verbose --features union) &&
([ $TRAVIS_RUST_VERSION != nightly ] || cargo test --verbose --all-features) &&
([ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose bench)
([ $TRAVIS_RUST_VERSION != nightly ] || cargo bench --verbose bench) &&
([ $TRAVIS_RUST_VERSION != nightly ] || bash ./scripts/run_miri.sh)
3 changes: 2 additions & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "smallvec"
version = "0.6.12"
version = "0.6.13"
authors = ["Simon Sapin <simon.sapin@exyr.org>"]
license = "MIT/Apache-2.0"
repository = "https://github.com/servo/rust-smallvec"
Expand All @@ -23,6 +23,7 @@ path = "lib.rs"

[dependencies]
serde = { version = "1", optional = true }
maybe-uninit = "2.0"

[dev_dependencies]
bincode = "1.0.1"
98 changes: 59 additions & 39 deletions lib.rs
Expand Up @@ -45,18 +45,21 @@ use alloc::vec::Vec;
#[cfg(feature = "serde")]
extern crate serde;

extern crate maybe_uninit;

#[cfg(not(feature = "std"))]
mod std {
pub use core::*;
}

use maybe_uninit::MaybeUninit;

use std::borrow::{Borrow, BorrowMut};
use std::cmp;
use std::fmt;
use std::hash::{Hash, Hasher};
use std::iter::{IntoIterator, FromIterator, repeat};
use std::mem;
use std::mem::ManuallyDrop;
use std::ops;
use std::ptr;
use std::slice;
Expand Down Expand Up @@ -275,26 +278,28 @@ impl<'a, T: 'a> Drop for Drain<'a,T> {

#[cfg(feature = "union")]
union SmallVecData<A: Array> {
inline: ManuallyDrop<A>,
inline: MaybeUninit<A>,
heap: (*mut A::Item, usize),
}

#[cfg(feature = "union")]
impl<A: Array> SmallVecData<A> {
#[inline]
unsafe fn inline(&self) -> &A {
&self.inline
unsafe fn inline(&self) -> *const A::Item {
self.inline.as_ptr() as *const A::Item
}
#[inline]
unsafe fn inline_mut(&mut self) -> &mut A {
&mut self.inline
unsafe fn inline_mut(&mut self) -> *mut A::Item {
self.inline.as_mut_ptr() as *mut A::Item
}
#[inline]
fn from_inline(inline: A) -> SmallVecData<A> {
SmallVecData { inline: ManuallyDrop::new(inline) }
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
SmallVecData { inline }
}
#[inline]
unsafe fn into_inline(self) -> A { ManuallyDrop::into_inner(self.inline) }
unsafe fn into_inline(self) -> MaybeUninit<A> {
self.inline
}
#[inline]
unsafe fn heap(&self) -> (*mut A::Item, usize) {
self.heap
Expand All @@ -311,34 +316,34 @@ impl<A: Array> SmallVecData<A> {

#[cfg(not(feature = "union"))]
enum SmallVecData<A: Array> {
Inline(ManuallyDrop<A>),
Inline(MaybeUninit<A>),
Heap((*mut A::Item, usize)),
}

#[cfg(not(feature = "union"))]
impl<A: Array> SmallVecData<A> {
#[inline]
unsafe fn inline(&self) -> &A {
unsafe fn inline(&self) -> *const A::Item {
match *self {
SmallVecData::Inline(ref a) => a,
SmallVecData::Inline(ref a) => a.as_ptr() as *const A::Item,
_ => debug_unreachable!(),
}
}
#[inline]
unsafe fn inline_mut(&mut self) -> &mut A {
unsafe fn inline_mut(&mut self) -> *mut A::Item {
match *self {
SmallVecData::Inline(ref mut a) => a,
SmallVecData::Inline(ref mut a) => a.as_mut_ptr() as *mut A::Item,
_ => debug_unreachable!(),
}
}
#[inline]
fn from_inline(inline: A) -> SmallVecData<A> {
SmallVecData::Inline(ManuallyDrop::new(inline))
fn from_inline(inline: MaybeUninit<A>) -> SmallVecData<A> {
SmallVecData::Inline(inline)
}
#[inline]
unsafe fn into_inline(self) -> A {
unsafe fn into_inline(self) -> MaybeUninit<A> {
match self {
SmallVecData::Inline(a) => ManuallyDrop::into_inner(a),
SmallVecData::Inline(a) => a,
_ => debug_unreachable!(),
}
}
Expand Down Expand Up @@ -403,11 +408,15 @@ impl<A: Array> SmallVec<A> {
/// Construct an empty vector
#[inline]
pub fn new() -> SmallVec<A> {
unsafe {
SmallVec {
capacity: 0,
data: SmallVecData::from_inline(mem::uninitialized()),
}
// Try to detect invalid custom implementations of `Array`. Hopefuly,
// this check should be optimized away entirely for valid ones.
assert!(
mem::size_of::<A>() == A::size() * mem::size_of::<A::Item>()
&& mem::align_of::<A>() >= mem::align_of::<A::Item>()
);
SmallVec {
capacity: 0,
data: SmallVecData::from_inline(MaybeUninit::uninit()),
}
}

Expand Down Expand Up @@ -447,10 +456,10 @@ impl<A: Array> SmallVec<A> {
pub fn from_vec(mut vec: Vec<A::Item>) -> SmallVec<A> {
if vec.capacity() <= A::size() {
unsafe {
let mut data = SmallVecData::<A>::from_inline(mem::uninitialized());
let mut data = SmallVecData::<A>::from_inline(MaybeUninit::uninit());
let len = vec.len();
vec.set_len(0);
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut().ptr_mut(), len);
ptr::copy_nonoverlapping(vec.as_ptr(), data.inline_mut(), len);

SmallVec {
capacity: len,
Expand Down Expand Up @@ -483,7 +492,7 @@ impl<A: Array> SmallVec<A> {
pub fn from_buf(buf: A) -> SmallVec<A> {
SmallVec {
capacity: A::size(),
data: SmallVecData::from_inline(buf),
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
}
}

Expand Down Expand Up @@ -523,7 +532,7 @@ impl<A: Array> SmallVec<A> {
pub unsafe fn from_buf_and_len_unchecked(buf: A, len: usize) -> SmallVec<A> {
SmallVec {
capacity: len,
data: SmallVecData::from_inline(buf),
data: SmallVecData::from_inline(MaybeUninit::new(buf)),
}
}

Expand Down Expand Up @@ -571,7 +580,7 @@ impl<A: Array> SmallVec<A> {
let (ptr, len) = self.data.heap();
(ptr, len, self.capacity)
} else {
(self.data.inline().ptr(), self.capacity, A::size())
(self.data.inline(), self.capacity, A::size())
}
}
}
Expand All @@ -584,7 +593,7 @@ impl<A: Array> SmallVec<A> {
let &mut (ptr, ref mut len_ptr) = self.data.heap_mut();
(ptr, len_ptr, self.capacity)
} else {
(self.data.inline_mut().ptr_mut(), &mut self.capacity, A::size())
(self.data.inline_mut(), &mut self.capacity, A::size())
}
}
}
Expand Down Expand Up @@ -651,8 +660,8 @@ impl<A: Array> SmallVec<A> {
if unspilled {
return;
}
self.data = SmallVecData::from_inline(mem::uninitialized());
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
self.capacity = len;
} else if new_cap != cap {
let mut vec = Vec::with_capacity(new_cap);
Expand Down Expand Up @@ -717,8 +726,8 @@ impl<A: Array> SmallVec<A> {
if self.inline_size() >= len {
unsafe {
let (ptr, len) = self.data.heap();
self.data = SmallVecData::from_inline(mem::uninitialized());
ptr::copy_nonoverlapping(ptr, self.data.inline_mut().ptr_mut(), len);
self.data = SmallVecData::from_inline(MaybeUninit::uninit());
ptr::copy_nonoverlapping(ptr, self.data.inline_mut(), len);
deallocate(ptr, self.capacity);
self.capacity = len;
}
Expand Down Expand Up @@ -883,7 +892,7 @@ impl<A: Array> SmallVec<A> {
unsafe {
let data = ptr::read(&self.data);
mem::forget(self);
Ok(data.into_inline())
Ok(data.into_inline().assume_init())
}
}
}
Expand Down Expand Up @@ -1041,8 +1050,12 @@ impl<A: Array> SmallVec<A> where A::Item: Copy {
SmallVec {
capacity: len,
data: SmallVecData::from_inline(unsafe {
let mut data: A = mem::uninitialized();
ptr::copy_nonoverlapping(slice.as_ptr(), data.ptr_mut(), len);
let mut data: MaybeUninit<A> = MaybeUninit::uninit();
ptr::copy_nonoverlapping(
slice.as_ptr(),
data.as_mut_ptr() as *mut A::Item,
len,
);
data
})
}
Expand Down Expand Up @@ -1587,8 +1600,8 @@ macro_rules! impl_array(
unsafe impl<T> Array for [T; $size] {
type Item = T;
fn size() -> usize { $size }
fn ptr(&self) -> *const T { self.as_ptr() }
fn ptr_mut(&mut self) -> *mut T { self.as_mut_ptr() }
fn ptr(&self) -> *const T { unimplemented!() }
fn ptr_mut(&mut self) -> *mut T { unimplemented!() }
}
)+
}
Expand Down Expand Up @@ -1889,7 +1902,7 @@ mod tests {
assert_eq!(&v.iter().map(|v| *v).collect::<Vec<_>>(), &[0, 5, 6, 1, 2, 3]);
}

#[cfg(feature = "std")]
#[cfg(all(feature = "std", not(miri)))] // Miri currently does not support unwinding
#[test]
// https://github.com/servo/rust-smallvec/issues/96
fn test_insert_many_panic() {
Expand Down Expand Up @@ -2338,6 +2351,13 @@ mod tests {
assert_eq!(v[..], ['a']);
}

// #139
#[test]
fn uninhabited() {
enum Void {}
let _sv = SmallVec::<[Void; 8]>::new();
}

#[test]
fn grow_spilled_same_size() {
let mut v: SmallVec<[u8; 2]> = SmallVec::new();
Expand Down
21 changes: 21 additions & 0 deletions scripts/run_miri.sh
@@ -0,0 +1,21 @@
#!/usr/bin/bash

set -ex

# Clean out our target dir, which may have artifacts compiled by a version of
# rust different from the one we're about to download.
cargo clean

# Install and run the latest version of nightly where miri built successfully.
# Taken from: https://github.com/rust-lang/miri#running-miri-on-ci

MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri)
echo "Installing latest nightly with Miri: $MIRI_NIGHTLY"
rustup default "$MIRI_NIGHTLY"

rustup component add miri
cargo miri setup

cargo miri test --verbose -- -- -Zunstable-options --exclude-should-panic
cargo miri test --verbose --features union -- -- -Zunstable-options --exclude-should-panic
cargo miri test --verbose --all-features -- -- -Zunstable-options --exclude-should-panic

0 comments on commit 7852204

Please sign in to comment.