From e24423091f0690a83e63ee234bee5627a86b51f0 Mon Sep 17 00:00:00 2001 From: Jonathan Reem Date: Sun, 26 Jul 2015 22:12:00 -0700 Subject: [PATCH] Implement Clone for Box<[T]> where T: Clone Closes #25097 --- src/liballoc/boxed.rs | 55 ++++++++++++++++++++++++++++++++- src/liballoc/lib.rs | 1 + src/libcollectionstest/slice.rs | 53 +++++++++++++++++++++++++++++++ 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 for Box+Send+'a> { } impl, U: ?Sized> CoerceUnsized> for Box {} + +#[stable(feature = "box_slice_clone", since = "1.3.0")] +impl 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 { + data: RawVec, + len: usize, + } + + impl BoxBuilder { + unsafe fn into_box(self) -> Box<[T]> { + let raw = ptr::read(&self.data); + mem::forget(self); + raw.into_box() + } + } + + impl Drop for BoxBuilder { + 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, + 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]>, @@ -250,13 +249,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;