Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prototype for MaybeUninit formulation of arrayvec #76

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 7 additions & 14 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
5 changes: 0 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
3 changes: 2 additions & 1 deletion src/array_string.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -53,7 +54,7 @@ impl<A: Array<Item=u8>> ArrayString<A> {
pub fn new() -> ArrayString<A> {
unsafe {
ArrayString {
xs: ::new_array(),
xs: uninitialized(),
len: Index::from(0),
}
}
Expand Down
52 changes: 23 additions & 29 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -51,19 +50,16 @@ 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};

mod array;
mod array_string;
mod range;
mod errors;
mod maybe_uninit;

use maybe_uninit::MaybeUninit;

pub use array::Array;
pub use range::RangeArgument;
Expand All @@ -72,14 +68,6 @@ pub use array_string::ArrayString;
pub use errors::CapacityError;


unsafe fn new_array<A: 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
Expand All @@ -93,17 +81,17 @@ unsafe fn new_array<A: Array>() -> A {
///
/// ArrayVec can be converted into a by value iterator.
pub struct ArrayVec<A: Array> {
xs: NoDrop<A>,
xs: MaybeUninit<A>,
len: A::Index,
}

impl<A: Array> Drop for ArrayVec<A> {
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
}
}

Expand All @@ -130,7 +118,7 @@ impl<A: Array> ArrayVec<A> {
/// ```
pub fn new() -> ArrayVec<A> {
unsafe {
ArrayVec { xs: NoDrop::new(new_array()), len: Index::from(0) }
ArrayVec { xs: MaybeUninit::uninitialized(), len: Index::from(0) }
}
}

Expand Down Expand Up @@ -463,7 +451,13 @@ impl<A: Array> ArrayVec<A> {

/// Remove all elements in the vector.
pub fn clear(&mut self) {
while let Some(_) = self.pop() { }
if mem::needs_drop::<A>() {
while let Some(_) = self.pop() { }
} else {
unsafe {
self.set_len(0);
}
}
}

/// Retains only the elements specified by the predicate.
Expand Down Expand Up @@ -536,7 +530,7 @@ impl<A: Array> ArrayVec<A> {
// 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.
Expand Down Expand Up @@ -568,13 +562,13 @@ impl<A: Array> ArrayVec<A> {
///
/// `Note:` This function may incur unproportionally large overhead
/// to move the array out, its performance is not optimal.
pub fn into_inner(self) -> Result<A, Self> {
pub fn into_inner(mut self) -> Result<A, Self> {
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)
}
}
Expand Down Expand Up @@ -602,7 +596,7 @@ impl<A: Array> Deref for ArrayVec<A> {
#[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())
}
}
}
Expand All @@ -612,7 +606,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
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)
}
}
}
Expand All @@ -628,7 +622,7 @@ impl<A: Array> DerefMut for ArrayVec<A> {
/// ```
impl<A: Array> From<A> for ArrayVec<A> {
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()) }
}
}

Expand Down
25 changes: 25 additions & 0 deletions src/maybe_uninit.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@


use std::mem::uninitialized;
use std::mem::ManuallyDrop;

#[repr(C)]
pub(crate) struct MaybeUninit<T>(ManuallyDrop<T>);

impl<T> MaybeUninit<T> {
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 _
}
}