From f5a4837df0885368352d118e1e71f4853bf55bf8 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Thu, 3 Apr 2014 22:28:45 +1100 Subject: std: override clone_from for Vec. A vector can reuse its allocation (and the allocations/resources of any contained values) when cloning into an already-instantiated vector, so we might as well do so. --- src/libstd/lib.rs | 1 + src/libstd/vec.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index fb6c1b4c8a3..7971c332b27 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -232,4 +232,5 @@ mod std { pub use to_str; pub use ty; pub use unstable; + pub use vec; } diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 69c3a85b2f1..e414ff25d43 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -310,11 +310,24 @@ impl Vec { impl Clone for Vec { fn clone(&self) -> Vec { - let mut vector = Vec::with_capacity(self.len()); - for element in self.iter() { - vector.push((*element).clone()) + self.iter().map(|x| x.clone()).collect() + } + + fn clone_from(&mut self, other: &Vec) { + // drop anything in self that will not be overwritten + if self.len() > other.len() { + self.truncate(other.len()) } - vector + + // reuse the contained values' allocations/resources. + for (place, thing) in self.mut_iter().zip(other.iter()) { + place.clone_from(thing) + } + + // self.len <= other.len due to the truncate above, so the + // slice here is always in-bounds. + let len = self.len(); + self.extend(other.slice_from(len).iter().map(|x| x.clone())); } } @@ -1475,4 +1488,39 @@ mod tests { assert!(values == Vec::from_slice([2u8, 3, 5, 6, 7])); } + + #[test] + fn test_clone() { + let v: Vec = vec!(); + let w = vec!(1, 2, 3); + + assert_eq!(v, v.clone()); + + let z = w.clone(); + assert_eq!(w, z); + // they should be disjoint in memory. + assert!(w.as_ptr() != z.as_ptr()) + } + + #[test] + fn test_clone_from() { + let mut v = vec!(); + let three = vec!(~1, ~2, ~3); + let two = vec!(~4, ~5); + // zero, long + v.clone_from(&three); + assert_eq!(v, three); + + // equal + v.clone_from(&three); + assert_eq!(v, three); + + // long, short + v.clone_from(&two); + assert_eq!(v, two); + + // short, long + v.clone_from(&three); + assert_eq!(v, three) + } } -- cgit 1.4.1-3-g733a5 From 898669c4e203ae91e2048fb6c0f8591c867bccc6 Mon Sep 17 00:00:00 2001 From: Daniel Micay Date: Wed, 2 Apr 2014 17:23:52 -0400 Subject: fix Option<~ZeroSizeType> 1778b6361627c5894bf75ffecf427573af02d390 provided the guarantee of no `exchange_free` calls for ~ZeroSizeType, so a sentinel can now be used without overhead. Closes #11998 --- src/librustc/middle/trans/expr.rs | 21 ++++++++++++++------- src/libstd/rt/global_heap.rs | 13 +++++++++++-- src/test/run-pass/empty-allocation-non-null.rs | 19 +++++++++++++++++++ 3 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 src/test/run-pass/empty-allocation-non-null.rs (limited to 'src/libstd') diff --git a/src/librustc/middle/trans/expr.rs b/src/librustc/middle/trans/expr.rs index bd8c84e85e5..49a4a3ed25c 100644 --- a/src/librustc/middle/trans/expr.rs +++ b/src/librustc/middle/trans/expr.rs @@ -67,7 +67,7 @@ use middle::typeck::MethodCall; use util::common::indenter; use util::ppaux::Repr; use util::nodemap::NodeMap; -use middle::trans::machine::llsize_of; +use middle::trans::machine::{llsize_of, llsize_of_alloc}; use middle::trans::type_::Type; use std::slice; @@ -1200,12 +1200,19 @@ fn trans_boxed_expr<'a>(bcx: &'a Block<'a>, let size = llsize_of(bcx.ccx(), llty); let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, contents_ty, heap_exchange, size); - let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); - fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope), - val, heap_exchange); - let bcx = trans_into(bcx, contents, SaveIn(val)); - fcx.pop_custom_cleanup_scope(custom_cleanup_scope); - immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() + // Unique boxes do not allocate for zero-size types. The standard library may assume + // that `free` is never called on the pointer returned for `~ZeroSizeType`. + if llsize_of_alloc(bcx.ccx(), llty) == 0 { + let bcx = trans_into(bcx, contents, SaveIn(val)); + immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() + } else { + let custom_cleanup_scope = fcx.push_custom_cleanup_scope(); + fcx.schedule_free_value(cleanup::CustomScope(custom_cleanup_scope), + val, heap_exchange); + let bcx = trans_into(bcx, contents, SaveIn(val)); + fcx.pop_custom_cleanup_scope(custom_cleanup_scope); + immediate_rvalue_bcx(bcx, val, box_ty).to_expr_datumblock() + } } else { let base::MallocResult { bcx, smart_ptr: bx, body } = base::malloc_general(bcx, contents_ty, heap); diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 23b23cf8af0..3917857e1af 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -64,12 +64,21 @@ pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 { } } +// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size +// allocations can point to this `static`. It would be incorrect to use a null +// pointer, due to enums assuming types like unique pointers are never null. +static EMPTY: () = (); + /// The allocator for unique pointers without contained managed pointers. #[cfg(not(test))] #[lang="exchange_malloc"] #[inline] -pub unsafe fn exchange_malloc(size: uint) -> *u8 { - malloc_raw(size) as *u8 +pub unsafe fn exchange_malloc(size: uint) -> *mut u8 { + if size == 0 { + &EMPTY as *() as *mut u8 + } else { + malloc_raw(size) + } } // FIXME: #7496 diff --git a/src/test/run-pass/empty-allocation-non-null.rs b/src/test/run-pass/empty-allocation-non-null.rs new file mode 100644 index 00000000000..9695296ec15 --- /dev/null +++ b/src/test/run-pass/empty-allocation-non-null.rs @@ -0,0 +1,19 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub fn main() { + assert!(Some(~()).is_some()); + + struct Foo; + assert!(Some(~Foo).is_some()); + + let xs: ~[()] = ~[]; + assert!(Some(xs).is_some()); +} -- cgit 1.4.1-3-g733a5 From 487fa9568b69753fecb74a8460109239f4bf3631 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Apr 2014 14:09:16 -0700 Subject: Test fixes from the rollup --- src/libstd/rt/global_heap.rs | 10 +++++----- src/libsyntax/abi.rs | 16 ++++++++-------- src/test/bench/rt-spawn-rate.rs | 10 ++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) (limited to 'src/libstd') diff --git a/src/libstd/rt/global_heap.rs b/src/libstd/rt/global_heap.rs index 3917857e1af..5c1b6cd4791 100644 --- a/src/libstd/rt/global_heap.rs +++ b/src/libstd/rt/global_heap.rs @@ -64,16 +64,16 @@ pub unsafe fn realloc_raw(ptr: *mut u8, size: uint) -> *mut u8 { } } -// The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size -// allocations can point to this `static`. It would be incorrect to use a null -// pointer, due to enums assuming types like unique pointers are never null. -static EMPTY: () = (); - /// The allocator for unique pointers without contained managed pointers. #[cfg(not(test))] #[lang="exchange_malloc"] #[inline] pub unsafe fn exchange_malloc(size: uint) -> *mut u8 { + // The compiler never calls `exchange_free` on ~ZeroSizeType, so zero-size + // allocations can point to this `static`. It would be incorrect to use a null + // pointer, due to enums assuming types like unique pointers are never null. + static EMPTY: () = (); + if size == 0 { &EMPTY as *() as *mut u8 } else { diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index a40899de931..17251d31351 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -193,12 +193,12 @@ fn indices_are_correct() { #[test] fn pick_uniplatform() { - assert_eq!(Stdcall.for_arch(OsLinux, X86), Some(Stdcall)); - assert_eq!(Stdcall.for_arch(OsLinux, Arm), None); - assert_eq!(System.for_arch(OsLinux, X86), Some(C)); - assert_eq!(System.for_arch(OsWin32, X86), Some(Stdcall)); - assert_eq!(System.for_arch(OsWin32, X86_64), Some(C)); - assert_eq!(System.for_arch(OsWin32, Arm), Some(C)); - assert_eq!(Stdcall.for_arch(OsWin32, X86), Some(Stdcall)); - assert_eq!(Stdcall.for_arch(OsWin32, X86_64), Some(Stdcall)); + assert_eq!(Stdcall.for_target(OsLinux, X86), Some(Stdcall)); + assert_eq!(Stdcall.for_target(OsLinux, Arm), None); + assert_eq!(System.for_target(OsLinux, X86), Some(C)); + assert_eq!(System.for_target(OsWin32, X86), Some(Stdcall)); + assert_eq!(System.for_target(OsWin32, X86_64), Some(C)); + assert_eq!(System.for_target(OsWin32, Arm), Some(C)); + assert_eq!(Stdcall.for_target(OsWin32, X86), Some(Stdcall)); + assert_eq!(Stdcall.for_target(OsWin32, X86_64), Some(Stdcall)); } diff --git a/src/test/bench/rt-spawn-rate.rs b/src/test/bench/rt-spawn-rate.rs index 5f445de069c..4f07660779b 100644 --- a/src/test/bench/rt-spawn-rate.rs +++ b/src/test/bench/rt-spawn-rate.rs @@ -8,6 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![no_start] + +extern crate green; +extern crate rustuv; + use std::task::spawn; use std::os; use std::uint; @@ -15,6 +20,11 @@ use std::uint; // Very simple spawn rate test. Spawn N tasks that do nothing and // return. +#[start] +fn start(argc: int, argv: **u8) -> int { + green::start(argc, argv, rustuv::event_loop, main) +} + fn main() { let args = os::args(); -- cgit 1.4.1-3-g733a5