diff options
| author | Jonathan Reem <jonathan.reem@gmail.com> | 2015-07-26 22:12:00 -0700 |
|---|---|---|
| committer | Jonathan Reem <jonathan.reem@gmail.com> | 2015-07-28 01:43:17 -0700 |
| commit | e24423091f0690a83e63ee234bee5627a86b51f0 (patch) | |
| tree | 3868b0ef0e26c53144c05e699acd757c2fe46ede | |
| parent | 184267cac6488c2f164dba469df5ef85533e148f (diff) | |
| download | rust-e24423091f0690a83e63ee234bee5627a86b51f0.tar.gz rust-e24423091f0690a83e63ee234bee5627a86b51f0.zip | |
Implement Clone for Box<[T]> where T: Clone
Closes #25097
| -rw-r--r-- | src/liballoc/boxed.rs | 55 | ||||
| -rw-r--r-- | src/liballoc/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcollectionstest/slice.rs | 53 | ||||
| -rw-r--r-- | src/libstd/ffi/c_str.rs | 10 |
4 files changed, 109 insertions, 10 deletions
diff --git a/src/liballoc/boxed.rs b/src/liballoc/boxed.rs index acf22094233..2b0aec5b727 100644 --- a/src/liballoc/boxed.rs +++ b/src/liballoc/boxed.rs @@ -56,6 +56,7 @@ use core::prelude::*; use heap; +use raw_vec::RawVec; use core::any::Any; use core::cmp::Ordering; @@ -65,7 +66,7 @@ use core::marker::{self, Unsize}; use core::mem; use core::ops::{CoerceUnsized, Deref, DerefMut}; use core::ops::{Placer, Boxed, Place, InPlace, BoxPlace}; -use core::ptr::Unique; +use core::ptr::{self, Unique}; use core::raw::{TraitObject}; /// A value that represents the heap. This is the default place that the `box` @@ -511,3 +512,55 @@ impl<'a,A,R> FnOnce<A> for Box<FnBox<A,Output=R>+Send+'a> { } impl<T: ?Sized+Unsize<U>, U: ?Sized> CoerceUnsized<Box<U>> for Box<T> {} + +#[stable(feature = "box_slice_clone", since = "1.3.0")] +impl<T: Clone> Clone for Box<[T]> { + fn clone(&self) -> Self { + let mut new = BoxBuilder { + data: RawVec::with_capacity(self.len()), + len: 0 + }; + + let mut target = new.data.ptr(); + + for item in self.iter() { + unsafe { + ptr::write(target, item.clone()); + target = target.offset(1); + }; + + new.len += 1; + } + + return unsafe { new.into_box() }; + + // Helper type for responding to panics correctly. + struct BoxBuilder<T> { + data: RawVec<T>, + len: usize, + } + + impl<T> BoxBuilder<T> { + unsafe fn into_box(self) -> Box<[T]> { + let raw = ptr::read(&self.data); + mem::forget(self); + raw.into_box() + } + } + + impl<T> Drop for BoxBuilder<T> { + fn drop(&mut self) { + let mut data = self.data.ptr(); + let max = unsafe { data.offset(self.len as isize) }; + + while data != max { + unsafe { + ptr::read(data); + data = data.offset(1); + } + } + } + } + } +} + diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index f66495c4057..d49d209955e 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -78,6 +78,7 @@ #![feature(core)] #![feature(core_intrinsics)] #![feature(core_prelude)] +#![feature(core_slice_ext)] #![feature(custom_attribute)] #![feature(fundamental)] #![feature(lang_items)] diff --git a/src/libcollectionstest/slice.rs b/src/libcollectionstest/slice.rs index c0ab11380d9..65706b292c6 100644 --- a/src/libcollectionstest/slice.rs +++ b/src/libcollectionstest/slice.rs @@ -1270,6 +1270,59 @@ fn test_to_vec() { assert_eq!(ys, [1, 2, 3]); } +#[test] +fn test_box_slice_clone() { + let data = vec![vec![0, 1], vec![0], vec![1]]; + let data2 = data.clone().into_boxed_slice().clone().to_vec(); + + assert_eq!(data, data2); +} + +#[test] +fn test_box_slice_clone_panics() { + use std::sync::Arc; + use std::sync::atomic::{AtomicUsize, Ordering}; + use std::thread::spawn; + + struct Canary { + count: Arc<AtomicUsize>, + panics: bool + } + + impl Drop for Canary { + fn drop(&mut self) { + self.count.fetch_add(1, Ordering::SeqCst); + } + } + + impl Clone for Canary { + fn clone(&self) -> Self { + if self.panics { panic!() } + + Canary { + count: self.count.clone(), + panics: self.panics + } + } + } + + let drop_count = Arc::new(AtomicUsize::new(0)); + let canary = Canary { count: drop_count.clone(), panics: false }; + let panic = Canary { count: drop_count.clone(), panics: true }; + + spawn(move || { + // When xs is dropped, +5. + let xs = vec![canary.clone(), canary.clone(), canary.clone(), + panic, canary].into_boxed_slice(); + + // When panic is cloned, +3. + xs.clone(); + }).join().unwrap_err(); + + // Total = 8 + assert_eq!(drop_count.load(Ordering::SeqCst), 8); +} + mod bench { use std::iter::repeat; use std::{mem, ptr}; diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs index c9fe6e7e0b1..6eb0719d9f6 100644 --- a/src/libstd/ffi/c_str.rs +++ b/src/libstd/ffi/c_str.rs @@ -11,7 +11,6 @@ use ascii; use borrow::{Cow, ToOwned, Borrow}; use boxed::Box; -use clone::Clone; use convert::{Into, From}; use cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}; use error::Error; @@ -62,7 +61,7 @@ use vec::Vec; /// } /// # } /// ``` -#[derive(PartialEq, PartialOrd, Eq, Ord, Hash)] +#[derive(PartialEq, PartialOrd, Eq, Ord, Hash, Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct CString { inner: Box<[u8]>, @@ -251,13 +250,6 @@ impl CString { } #[stable(feature = "rust1", since = "1.0.0")] -impl Clone for CString { - fn clone(&self) -> Self { - CString { inner: self.inner.to_owned().into_boxed_slice() } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] impl Deref for CString { type Target = CStr; |
