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:
+43
-7
@@ -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
@@ -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]
|
||||||
|
|||||||
Reference in New Issue
Block a user