From 19dc3b50bd63489988eb8fc83d25b08ca83df151 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Sat, 17 May 2014 00:56:00 -0700 Subject: core: Stabilize the mem module Excluding the functions inherited from the cast module last week (with marked stability levels), these functions received the following treatment. * size_of - this method has become #[stable] * nonzero_size_of/nonzero_size_of_val - these methods have been removed * min_align_of - this method is now #[stable] * pref_align_of - this method has been renamed without the `pref_` prefix, and it is the "default alignment" now. This decision is in line with what clang does (see url linked in comment on function). This function is now #[stable]. * init - renamed to zeroed and marked #[stable] * uninit - marked #[stable] * move_val_init - renamed to overwrite and marked #[stable] * {from,to}_{be,le}{16,32,64} - all functions marked #[stable] * swap/replace/drop - marked #[stable] * size_of_val/min_align_of_val/align_of_val - these functions are marked #[unstable], but will continue to exist in some form. Concerns have been raised about their `_val` prefix. [breaking-change] --- src/libcore/mem.rs | 208 +++++++++++++++++++++++++++------------- src/libcore/should_not_exist.rs | 8 +- src/libcore/slice.rs | 5 +- 3 files changed, 148 insertions(+), 73 deletions(-) (limited to 'src/libcore') diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs index c5c6d751777..aa7a8f0f8b6 100644 --- a/src/libcore/mem.rs +++ b/src/libcore/mem.rs @@ -19,31 +19,36 @@ use intrinsics::{bswap16, bswap32, bswap64}; /// Returns the size of a type in bytes. #[inline] +#[stable] pub fn size_of() -> uint { unsafe { intrinsics::size_of::() } } /// Returns the size of the type that `_val` points to in bytes. #[inline] +#[unstable = "the name of this function may change slightly before stabilizing"] pub fn size_of_val(_val: &T) -> uint { size_of::() } -/// Returns the size of a type in bytes, or 1 if the actual size is zero. -/// -/// Useful for building structures containing variable-length arrays. +/// Deprecated, this function will be removed soon #[inline] +#[deprecated = "this function will be removed soon"] pub fn nonzero_size_of() -> uint { match size_of::() { 0 => 1, - x => x + n => n, } } -/// Returns the size in bytes of the type of the value that `_val` points to. +/// Deprecated, this function will be removed soon #[inline] -pub fn nonzero_size_of_val(_val: &T) -> uint { - nonzero_size_of::() +#[deprecated = "this function will be removed soon"] +pub fn nonzero_size_of_val(val: &T) -> uint { + match size_of_val::(val) { + 0 => 1, + n => n, + } } /// Returns the ABI-required minimum alignment of a type @@ -51,6 +56,7 @@ pub fn nonzero_size_of_val(_val: &T) -> uint { /// This is the alignment used for struct fields. It may be smaller /// than the preferred alignment. #[inline] +#[stable] pub fn min_align_of() -> uint { unsafe { intrinsics::min_align_of::() } } @@ -58,44 +64,100 @@ pub fn min_align_of() -> uint { /// Returns the ABI-required minimum alignment of the type of the value that /// `_val` points to #[inline] +#[unstable = "the name of this function may change slightly before stabilizing"] pub fn min_align_of_val(_val: &T) -> uint { min_align_of::() } -/// Returns the preferred alignment of a type +/// Returns the alignment in memory for a type. +/// +/// This function will return the alignment, in bytes, of a type in memory. If +/// the alignment returned is adhered to, then the type is guaranteed to +/// function properly. #[inline] -pub fn pref_align_of() -> uint { +#[stable] +pub fn align_of() -> uint { + // We use the preferred alignment as the default alignment for a type. This + // appears to be what clang migrated towards as well: + // + // http://lists.cs.uiuc.edu/pipermail/cfe-commits/Week-of-Mon-20110725/044411.html unsafe { intrinsics::pref_align_of::() } } -/// Returns the preferred alignment of the type of the value that -/// `_val` points to +/// Returns the alignment of the type of the value that `_val` points to. +/// +/// This is similar to `align_of`, but function will properly handle types such +/// as trait objects (in the future), returning the alignment for an arbitrary +/// value at runtime. #[inline] -pub fn pref_align_of_val(_val: &T) -> uint { - pref_align_of::() +#[unstable = "the name of this function may change slightly before stabilizing"] +pub fn align_of_val(_val: &T) -> uint { + align_of::() } +/// Deprecated, this function has been renamed to align_of +#[inline] +#[deprecated = "use mem::align_of instead"] +pub fn pref_align_of() -> uint { align_of::() } + +/// Deprecated, this function has been renamed to align_of_val +#[inline] +#[deprecated = "use mem::align_of_val instead"] +pub fn pref_align_of_val(val: &T) -> uint { align_of_val(val) } + /// Create a value initialized to zero. /// -/// `init` is unsafe because it returns a zeroed-out datum, -/// which is unsafe unless T is Copy. +/// This function is similar to allocating space for a a local variable and +/// zeroing it out (an unsafe operation). +/// +/// Care must be taken when using this function, if the type `T` has a +/// destructor and the value falls out of scope (due to unwinding or returning) +/// before being initialized, then the destructor will run on zeroed +/// data, likely leading to crashes. +/// +/// This is useful for FFI functions sometimes, but should generally be avoided. #[inline] -pub unsafe fn init() -> T { +#[unstable = "the name of this function is subject to change"] +pub unsafe fn zeroed() -> T { intrinsics::init() } +/// Deprecated, use zeroed() instead +#[inline] +#[deprecated = "this function has been renamed to zeroed()"] +pub unsafe fn init() -> T { zeroed() } + /// Create an uninitialized value. +/// +/// Care must be taken when using this function, if the type `T` has a +/// destructor and the value falls out of scope (due to unwinding or returning) +/// before being initialized, then the destructor will run on uninitialized +/// data, likely leading to crashes. +/// +/// This is useful for FFI functions sometimes, but should generally be avoided. #[inline] +#[unstable = "the name of this function is subject to change"] pub unsafe fn uninit() -> T { intrinsics::uninit() } -/// Move a value to an uninitialized memory location. +/// Unsafely overwrite a memory location with the given value without destroying +/// the old value. /// -/// Drop glue is not run on the destination. +/// This operation is unsafe because it does not destroy the previous value +/// contained at the location `dst`. This could leak allocations or resources, +/// so care must be taken to previously deallocate the value at `dst`. +#[inline] +#[unstable = "the name of this function is subject to change"] +pub unsafe fn overwrite(dst: *mut T, src: T) { + intrinsics::move_val_init(&mut *dst, src) +} + +/// Deprecated, use move_val_init() instead #[inline] +#[deprecated = "this function has been renamed to move_val_init()"] pub unsafe fn move_val_init(dst: &mut T, src: T) { - intrinsics::move_val_init(dst, src) + overwrite(dst, src) } /// Convert an u16 to little endian from the target's endianness. @@ -106,126 +168,150 @@ pub unsafe fn move_val_init(dst: &mut T, src: T) { /// Convert an u16 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_le16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_le16(x: u16) -> u16 { unsafe { bswap16(x) } } /// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: u32) -> u32 { x } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn to_le32(x: u32) -> u32 { x } /// Convert an u32 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_le32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_le32(x: u32) -> u32 { unsafe { bswap32(x) } } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: u64) -> u64 { x } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn to_le64(x: u64) -> u64 { x } /// Convert an u64 to little endian from the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_le64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_le64(x: u64) -> u64 { unsafe { bswap64(x) } } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn to_be16(x: u16) -> u16 { unsafe { bswap16(x) } } /// Convert an u16 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_be16(x: u16) -> u16 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_be16(x: u16) -> u16 { x } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn to_be32(x: u32) -> u32 { unsafe { bswap32(x) } } /// Convert an u32 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_be32(x: u32) -> u32 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_be32(x: u32) -> u32 { x } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn to_be64(x: u64) -> u64 { unsafe { bswap64(x) } } /// Convert an u64 to big endian from the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn to_be64(x: u64) -> u64 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn to_be64(x: u64) -> u64 { x } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: u16) -> u16 { x } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_le16(x: u16) -> u16 { x } /// Convert an u16 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_le16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_le16(x: u16) -> u16 { unsafe { bswap16(x) } } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: u32) -> u32 { x } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_le32(x: u32) -> u32 { x } /// Convert an u32 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_le32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_le32(x: u32) -> u32 { unsafe { bswap32(x) } } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: u64) -> u64 { x } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_le64(x: u64) -> u64 { x } /// Convert an u64 from little endian to the target's endianness. /// /// On little endian, this is a no-op. On big endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_le64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_le64(x: u64) -> u64 { unsafe { bswap64(x) } } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: u16) -> u16 { unsafe { bswap16(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_be16(x: u16) -> u16 { unsafe { bswap16(x) } } /// Convert an u16 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_be16(x: u16) -> u16 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_be16(x: u16) -> u16 { x } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: u32) -> u32 { unsafe { bswap32(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_be32(x: u32) -> u32 { unsafe { bswap32(x) } } /// Convert an u32 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_be32(x: u32) -> u32 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_be32(x: u32) -> u32 { x } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: u64) -> u64 { unsafe { bswap64(x) } } +#[cfg(target_endian = "little")] #[inline] #[stable] +pub fn from_be64(x: u64) -> u64 { unsafe { bswap64(x) } } /// Convert an u64 from big endian to the target's endianness. /// /// On big endian, this is a no-op. On little endian, the bytes are swapped. -#[cfg(target_endian = "big")] #[inline] pub fn from_be64(x: u64) -> u64 { x } +#[cfg(target_endian = "big")] #[inline] #[stable] +pub fn from_be64(x: u64) -> u64 { x } /** * Swap the values at two mutable locations of the same type, without * deinitialising or copying either one. */ #[inline] +#[stable] pub fn swap(x: &mut T, y: &mut T) { unsafe { // Give ourselves some scratch space to work with @@ -279,6 +365,7 @@ pub fn swap(x: &mut T, y: &mut T) { * ``` */ #[inline] +#[stable] pub fn replace(dest: &mut T, mut src: T) -> T { swap(dest, &mut src); src @@ -304,6 +391,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("{}", *borrow); /// ``` #[inline] +#[stable] pub fn drop(_x: T) { } /// Moves a thing into the void. @@ -415,27 +503,11 @@ mod tests { assert_eq!(size_of_val(&1u64), 8); } - #[test] - fn nonzero_size_of_basic() { - type Z = [i8, ..0]; - assert_eq!(size_of::(), 0u); - assert_eq!(nonzero_size_of::(), 1u); - assert_eq!(nonzero_size_of::(), size_of::()); - } - - #[test] - fn nonzero_size_of_val_basic() { - let z = [0u8, ..0]; - assert_eq!(size_of_val(&z), 0u); - assert_eq!(nonzero_size_of_val(&z), 1u); - assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u)); - } - #[test] fn align_of_basic() { - assert_eq!(pref_align_of::(), 1u); - assert_eq!(pref_align_of::(), 2u); - assert_eq!(pref_align_of::(), 4u); + assert_eq!(align_of::(), 1u); + assert_eq!(align_of::(), 2u); + assert_eq!(align_of::(), 4u); } #[test] @@ -443,22 +515,22 @@ mod tests { #[cfg(target_arch = "arm")] #[cfg(target_arch = "mips")] fn align_of_32() { - assert_eq!(pref_align_of::(), 4u); - assert_eq!(pref_align_of::<*uint>(), 4u); + assert_eq!(align_of::(), 4u); + assert_eq!(align_of::<*uint>(), 4u); } #[test] #[cfg(target_arch = "x86_64")] fn align_of_64() { - assert_eq!(pref_align_of::(), 8u); - assert_eq!(pref_align_of::<*uint>(), 8u); + assert_eq!(align_of::(), 8u); + assert_eq!(align_of::<*uint>(), 8u); } #[test] fn align_of_val_basic() { - assert_eq!(pref_align_of_val(&1u8), 1u); - assert_eq!(pref_align_of_val(&1u16), 2u); - assert_eq!(pref_align_of_val(&1u32), 4u); + assert_eq!(align_of_val(&1u8), 1u); + assert_eq!(align_of_val(&1u16), 2u); + assert_eq!(align_of_val(&1u32), 4u); } #[test] diff --git a/src/libcore/should_not_exist.rs b/src/libcore/should_not_exist.rs index b55952e7059..ccca52c573d 100644 --- a/src/libcore/should_not_exist.rs +++ b/src/libcore/should_not_exist.rs @@ -171,15 +171,17 @@ impl Clone for ~[A] { unsafe { let ret = alloc(size) as *mut Vec; - (*ret).fill = len * mem::nonzero_size_of::(); - (*ret).alloc = len * mem::nonzero_size_of::(); + let a_size = mem::size_of::(); + let a_size = if a_size == 0 {1} else {a_size}; + (*ret).fill = len * a_size; + (*ret).alloc = len * a_size; let mut i = 0; let p = &mut (*ret).data as *mut _ as *mut A; try_finally( &mut i, (), |i, ()| while *i < len { - mem::move_val_init( + mem::overwrite( &mut(*p.offset(*i as int)), self.unsafe_ref(*i).clone()); *i += 1; diff --git a/src/libcore/slice.rs b/src/libcore/slice.rs index d08e5492c82..755c6738b4a 100644 --- a/src/libcore/slice.rs +++ b/src/libcore/slice.rs @@ -1122,7 +1122,7 @@ impl<'a,T> MutableVector<'a, T> for &'a mut [T] { #[inline] unsafe fn init_elem(self, i: uint, val: T) { - mem::move_val_init(&mut (*self.as_mut_ptr().offset(i as int)), val); + mem::overwrite(&mut (*self.as_mut_ptr().offset(i as int)), val); } #[inline] @@ -1306,7 +1306,8 @@ macro_rules! iterator { #[inline] fn size_hint(&self) -> (uint, Option) { let diff = (self.end as uint) - (self.ptr as uint); - let exact = diff / mem::nonzero_size_of::(); + let size = mem::size_of::(); + let exact = diff / (if size == 0 {1} else {size}); (exact, Some(exact)) } } -- cgit 1.4.1-3-g733a5