Use a non-dropping enum directly

Don't use NoDrop as a separate abstraction: Then we have two drop flags,
one for ArrayVec and one for NoDrop. Instead import the logic from
NoDrop. The result is a much smaller ArrayVec value.
This commit is contained in:
root
2015-07-30 16:11:08 +02:00
parent 3634fa4633
commit cf273fec1f
2 changed files with 47 additions and 11 deletions
+43 -7
View File
@@ -1,7 +1,4 @@
extern crate odds; extern crate odds;
extern crate nodrop;
use nodrop::NoDrop;
use std::iter; use std::iter;
use std::mem; use std::mem;
@@ -17,6 +14,8 @@ use std::borrow::{Borrow, BorrowMut};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::fmt; use std::fmt;
use odds::debug_assert_unreachable;
mod array; mod array;
pub use array::Array; pub use array::Array;
pub use odds::IndexRange as RangeArgument; pub use odds::IndexRange as RangeArgument;
@@ -27,10 +26,17 @@ unsafe fn new_array<A: Array>() -> A {
// Note: Returning an uninitialized value here only works // Note: Returning an uninitialized value here only works
// if we can be sure the data is never used. The nullable pointer // if we can be sure the data is never used. The nullable pointer
// inside enum optimization conflicts with this this for example, // 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() mem::uninitialized()
} }
/// repr(u8) - Make sure the non-nullable pointer optimization does not occur!
#[repr(u8)]
enum NoDrop<T> {
Alive(T),
Dropped,
}
/// A vector with a fixed capacity. /// A vector with a fixed capacity.
/// ///
/// The **ArrayVec** is a vector backed by a fixed size array. It keeps track of /// The **ArrayVec** is a vector backed by a fixed size array. It keeps track of
@@ -50,8 +56,13 @@ pub struct ArrayVec<A: Array> {
impl<A: Array> Drop for ArrayVec<A> { impl<A: Array> Drop for ArrayVec<A> {
fn drop(&mut self) { fn drop(&mut self) {
// clear all elements, then NoDrop inhibits drop of inner array // clear all elements
while let Some(_) = self.pop() { } while let Some(_) = self.pop() { }
// inhibit drop
unsafe {
ptr::write(&mut self.xs, NoDrop::Dropped);
}
} }
} }
@@ -73,7 +84,7 @@ impl<A: Array> ArrayVec<A> {
/// ``` /// ```
pub fn new() -> ArrayVec<A> { pub fn new() -> ArrayVec<A> {
unsafe { unsafe {
ArrayVec { xs: NoDrop::new(new_array()), len: Index::zero() } ArrayVec { xs: NoDrop::Alive(new_array()), len: Index::zero() }
} }
} }
@@ -364,6 +375,31 @@ impl<A: Array> DerefMut for ArrayVec<A> {
} }
} }
impl<T> Deref for NoDrop<T> {
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<T> DerefMut for NoDrop<T> {
// 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. /// Create an **ArrayVec** from an array.
/// ///
/// ## Examples /// ## Examples
@@ -376,7 +412,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
/// ``` /// ```
impl<A: Array> From<A> for ArrayVec<A> { impl<A: Array> From<A> for ArrayVec<A> {
fn from(array: A) -> Self { 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()) }
} }
} }
+4 -4
View File
@@ -127,15 +127,15 @@ fn test_is_send_sync() {
#[test] #[test]
fn test_compact_size() { fn test_compact_size() {
// Future rust will kill these drop flags! // 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]>; type ByteArray = ArrayVec<[u8; 4]>;
println!("{}", mem::size_of::<ByteArray>()); println!("{}", mem::size_of::<ByteArray>());
assert!(mem::size_of::<ByteArray>() <= 8); assert!(mem::size_of::<ByteArray>() <= 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]>; type QuadArray = ArrayVec<[u32; 3]>;
println!("{}", mem::size_of::<QuadArray>()); println!("{}", mem::size_of::<QuadArray>());
assert!(mem::size_of::<QuadArray>() <= 24); assert!(mem::size_of::<QuadArray>() <= 20);
} }
#[test] #[test]