From c0b2bce838f2ebe9ab4d4c81f1126e26eaa6251b Mon Sep 17 00:00:00 2001 From: bluss Date: Fri, 20 Oct 2017 23:41:31 +0200 Subject: [PATCH 1/3] Prototype for MaybeUninit formulation of arrayvec - Testing ideas for arrayvec 1.0 - Looking at what is well defined and what's not --- src/array_string.rs | 3 ++- src/lib.rs | 52 ++++++++++++++++++++------------------------- src/maybe_uninit.rs | 25 ++++++++++++++++++++++ 3 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 src/maybe_uninit.rs diff --git a/src/array_string.rs b/src/array_string.rs index a02100ad..a375b6e4 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -3,6 +3,7 @@ use std::cmp; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; +use std::mem::uninitialized; use std::ptr; use std::ops::{Deref, DerefMut}; use std::str; @@ -53,7 +54,7 @@ impl> ArrayString { pub fn new() -> ArrayString { unsafe { ArrayString { - xs: ::new_array(), + xs: uninitialized(), len: Index::from(0), } } diff --git a/src/lib.rs b/src/lib.rs index b7510772..6e33b507 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,6 @@ #![doc(html_root_url="https://docs.rs/arrayvec/0.4/")] #![cfg_attr(not(feature="std"), no_std)] extern crate odds; -extern crate nodrop; #[cfg(feature="serde-1")] extern crate serde; @@ -51,12 +50,6 @@ use std::fmt; #[cfg(feature="std")] use std::io; -#[cfg(not(feature="use_union"))] -use nodrop::NoDrop; - -#[cfg(feature="use_union")] -use std::mem::ManuallyDrop as NoDrop; - #[cfg(feature="serde-1")] use serde::{Serialize, Deserialize, Serializer, Deserializer}; @@ -64,6 +57,9 @@ mod array; mod array_string; mod range; mod errors; +mod maybe_uninit; + +use maybe_uninit::MaybeUninit; pub use array::Array; pub use range::RangeArgument; @@ -72,14 +68,6 @@ pub use array_string::ArrayString; pub use errors::CapacityError; -unsafe fn new_array() -> A { - // Note: Returning an uninitialized value here only works - // if we can be sure the data is never used. The nullable pointer - // inside enum optimization conflicts with this this for example, - // so we need to be extra careful. See `NoDrop` enum. - mem::uninitialized() -} - /// A vector with a fixed capacity. /// /// The `ArrayVec` is a vector backed by a fixed size array. It keeps track of @@ -93,17 +81,17 @@ unsafe fn new_array() -> A { /// /// ArrayVec can be converted into a by value iterator. pub struct ArrayVec { - xs: NoDrop, + xs: MaybeUninit, len: A::Index, } impl Drop for ArrayVec { fn drop(&mut self) { - self.clear(); + unsafe { + ptr::drop_in_place(&mut self[..]); + } - // NoDrop inhibits array's drop - // panic safety: NoDrop::drop will trigger on panic, so the inner - // array will not drop even after panic. + // ManuallyDrop inhibits array's drop } } @@ -130,7 +118,7 @@ impl ArrayVec { /// ``` pub fn new() -> ArrayVec { unsafe { - ArrayVec { xs: NoDrop::new(new_array()), len: Index::from(0) } + ArrayVec { xs: MaybeUninit::uninitialized(), len: Index::from(0) } } } @@ -463,7 +451,13 @@ impl ArrayVec { /// Remove all elements in the vector. pub fn clear(&mut self) { - while let Some(_) = self.pop() { } + if mem::needs_drop::() { + while let Some(_) = self.pop() { } + } else { + unsafe { + self.set_len(0); + } + } } /// Retains only the elements specified by the predicate. @@ -536,7 +530,7 @@ impl ArrayVec { // Memory safety // // When the Drain is first created, it shortens the length of - // the source vector to make sure no uninitalized or moved-from elements + // the source vector to make sure no uninitialized or moved-from elements // are accessible at all if the Drain's destructor never gets to run. // // Drain will ptr::read out the values to remove. @@ -568,13 +562,13 @@ impl ArrayVec { /// /// `Note:` This function may incur unproportionally large overhead /// to move the array out, its performance is not optimal. - pub fn into_inner(self) -> Result { + pub fn into_inner(mut self) -> Result { if self.len() < self.capacity() { Err(self) } else { unsafe { - let array = ptr::read(&*self.xs); - mem::forget(self); + let array = ptr::read(self.xs.ptr()); + self.set_len(0); Ok(array) } } @@ -602,7 +596,7 @@ impl Deref for ArrayVec { #[inline] fn deref(&self) -> &[A::Item] { unsafe { - slice::from_raw_parts(self.xs.as_ptr(), self.len()) + slice::from_raw_parts((*self.xs.ptr()).as_ptr(), self.len()) } } } @@ -612,7 +606,7 @@ impl DerefMut for ArrayVec { fn deref_mut(&mut self) -> &mut [A::Item] { let len = self.len(); unsafe { - slice::from_raw_parts_mut(self.xs.as_mut_ptr(), len) + slice::from_raw_parts_mut((*self.xs.ptr_mut()).as_mut_ptr(), len) } } } @@ -628,7 +622,7 @@ impl DerefMut for ArrayVec { /// ``` impl From for ArrayVec { fn from(array: A) -> Self { - ArrayVec { xs: NoDrop::new(array), len: Index::from(A::capacity()) } + ArrayVec { xs: MaybeUninit::from(array), len: Index::from(A::capacity()) } } } diff --git a/src/maybe_uninit.rs b/src/maybe_uninit.rs new file mode 100644 index 00000000..1e39e1e2 --- /dev/null +++ b/src/maybe_uninit.rs @@ -0,0 +1,25 @@ + + +use std::mem::uninitialized; +use std::mem::ManuallyDrop; + +#[repr(C)] +pub(crate) struct MaybeUninit(ManuallyDrop); + +impl MaybeUninit { + pub unsafe fn uninitialized() -> Self { + uninitialized() + } + + pub fn from(value: T) -> Self { + MaybeUninit(ManuallyDrop::new(value)) + } + + pub fn ptr(&self) -> *const T { + self as *const _ as _ + } + pub fn ptr_mut(&mut self) -> *mut T { + self as *mut _ as _ + } +} + From 0d3009739a10159209e699a47f29cbef18176a7b Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 21 Oct 2017 11:51:58 +0200 Subject: [PATCH 2/3] MAINT: no nodrop dependency --- Cargo.toml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c545a101..6fc31d17 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,11 +15,6 @@ categories = ["data-structures", "no-std"] version = "0.2.23" default-features = false -[dependencies.nodrop] -version = "0.1.8" -path = "nodrop" -default-features = false - [dependencies.serde] version = "1.0" optional = true From ad54aeb1697467d1f034d5f1466b815cef34221a Mon Sep 17 00:00:00 2001 From: bluss Date: Sat, 21 Oct 2017 11:54:13 +0200 Subject: [PATCH 3/3] MAINT: update .travis --- .travis.yml | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1424602d..58113193 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,34 +4,27 @@ env: - FEATURES='serde-1' matrix: include: - - rust: 1.14.0 + - rust: 1.21.0 - rust: stable env: - NODEFAULT=1 - - NODROP_FEATURES='use_needs_drop' - rust: beta - rust: nightly env: - NODEFAULT=1 - rust: nightly - env: - - NODROP_FEATURES='use_needs_drop' - rust: nightly env: - - FEATURES='serde use_union' - - NODROP_FEATURES='use_union' + - FEATURES='serde' branches: only: - master - 0.3 script: - | - ([ ! -z "$NODROP_FEATURES" ] || cargo build --verbose --features "$FEATURES") && + cargo build --verbose --features "$FEATURES" && ([ "$NODEFAULT" != 1 ] || cargo build --verbose --no-default-features) && - ([ ! -z "$NODROP_FEATURES" ] || cargo test --verbose --features "$FEATURES") && - ([ ! -z "$NODROP_FEATURES" ] || cargo test --release --verbose --features "$FEATURES") && - ([ ! -z "$NODROP_FEATURES" ] || cargo bench --verbose --features "$FEATURES" -- --test) && - ([ ! -z "$NODROP_FEATURES" ] || cargo doc --verbose --features "$FEATURES") && - ([ "$NODEFAULT" != 1 ] || cargo build --verbose --manifest-path=nodrop/Cargo.toml --no-default-features) && - cargo test --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" && - cargo bench --verbose --manifest-path=nodrop/Cargo.toml --features "$NODROP_FEATURES" -- --test + cargo test --verbose --features "$FEATURES" && + cargo test --release --verbose --features "$FEATURES" && + cargo bench --verbose --features "$FEATURES" -- --test && + cargo doc --verbose --features "$FEATURES"