diff --git a/Cargo.toml b/Cargo.toml index 12184af..c6c15a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "arrayvec" -version = "0.3.7" +version = "0.3.8" authors = ["bluss"] license = "MIT/Apache-2.0" diff --git a/README.rst b/README.rst index 521989b..921ed38 100644 --- a/README.rst +++ b/README.rst @@ -22,6 +22,11 @@ __ http://bluss.github.io/arrayvec Recent Changes -------------- +- 0.3.8 + + - Inline the non-dropping logic to remove one drop flag in the + ArrayVec representation. + - 0.3.7 - Added method .into_inner() diff --git a/src/lib.rs b/src/lib.rs index c6e54ca..9cb6dc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,4 @@ extern crate odds; -extern crate nodrop; - -use nodrop::NoDrop; use std::iter; use std::mem; @@ -17,6 +14,8 @@ use std::borrow::{Borrow, BorrowMut}; use std::hash::{Hash, Hasher}; use std::fmt; +use odds::debug_assert_unreachable; + mod array; pub use array::Array; pub use odds::IndexRange as RangeArgument; @@ -27,10 +26,17 @@ 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 `Flag` enum. + // so we need to be extra careful. See `NoDrop` enum. mem::uninitialized() } +/// repr(u8) - Make sure the non-nullable pointer optimization does not occur! +#[repr(u8)] +enum NoDrop { + Alive(T), + Dropped, +} + /// A vector with a fixed capacity. /// /// The **ArrayVec** is a vector backed by a fixed size array. It keeps track of @@ -50,8 +56,13 @@ pub struct ArrayVec { impl Drop for ArrayVec { fn drop(&mut self) { - // clear all elements, then NoDrop inhibits drop of inner array + // clear all elements while let Some(_) = self.pop() { } + + // inhibit drop + unsafe { + ptr::write(&mut self.xs, NoDrop::Dropped); + } } } @@ -73,7 +84,7 @@ impl ArrayVec { /// ``` pub fn new() -> ArrayVec { unsafe { - ArrayVec { xs: NoDrop::new(new_array()), len: Index::zero() } + ArrayVec { xs: NoDrop::Alive(new_array()), len: Index::zero() } } } @@ -364,6 +375,31 @@ impl DerefMut for ArrayVec { } } +impl Deref for NoDrop { + type Target = T; + + // Use type invariant, always Alive. + #[inline] + fn deref(&self) -> &T { + match *self { + NoDrop::Alive(ref inner) => inner, + _ => unsafe { debug_assert_unreachable() } + } + } +} + +impl DerefMut for NoDrop { + // Use type invariant, always Alive. + #[inline] + fn deref_mut(&mut self) -> &mut T { + match *self { + NoDrop::Alive(ref mut inner) => inner, + _ => unsafe { debug_assert_unreachable() } + } + } +} + + /// Create an **ArrayVec** from an array. /// /// ## Examples @@ -376,7 +412,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: NoDrop::Alive(array), len: Index::from(A::capacity()) } } } diff --git a/tests/tests.rs b/tests/tests.rs index c2cf272..60bbcde 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -127,15 +127,15 @@ fn test_is_send_sync() { #[test] fn test_compact_size() { // Future rust will kill these drop flags! - // 4 elements size + 1 len + 1 enum tag + [1 drop flag] + [1 drop flag nodrop] + // 4 elements size + 1 len + 1 enum tag + [1 drop flag] type ByteArray = ArrayVec<[u8; 4]>; println!("{}", mem::size_of::()); - assert!(mem::size_of::() <= 8); + assert!(mem::size_of::() <= 7); - // 12 element size + 1 len + 1 drop flag + 2 padding + 1 enum tag + 3 padding + // 12 element size + 1 enum tag + 3 padding + 1 len + 1 drop flag + 2 padding type QuadArray = ArrayVec<[u32; 3]>; println!("{}", mem::size_of::()); - assert!(mem::size_of::() <= 24); + assert!(mem::size_of::() <= 20); } #[test]