diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-04-30 20:13:05 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-05-07 08:12:48 -0700 |
| commit | dca8a0d6e4d1848ead898b3fa5b1e6c940c85b87 (patch) | |
| tree | 219fe4ec5952f3b07227852529c0007285dcdd14 /src/libcore | |
| parent | 5b75e44fb01f0eda10ce8d8df92b80945d894768 (diff) | |
| download | rust-dca8a0d6e4d1848ead898b3fa5b1e6c940c85b87.tar.gz rust-dca8a0d6e4d1848ead898b3fa5b1e6c940c85b87.zip | |
core: Inherit the mem module
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/lib.rs | 1 | ||||
| -rw-r--r-- | src/libcore/mem.rs | 458 |
2 files changed, 459 insertions, 0 deletions
diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index b76d3b84254..a0cadd6fc72 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -24,3 +24,4 @@ /* Core modules for ownership management */ pub mod intrinsics; +pub mod mem; diff --git a/src/libcore/mem.rs b/src/libcore/mem.rs new file mode 100644 index 00000000000..860304232d4 --- /dev/null +++ b/src/libcore/mem.rs @@ -0,0 +1,458 @@ +// Copyright 2012-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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Basic functions for dealing with memory +//! +//! This module contains functions for querying the size and alignment of +//! types, initializing and manipulating memory. + +use cast; +use ptr; +use intrinsics; +use intrinsics::{bswap16, bswap32, bswap64}; + +/// Returns the size of a type in bytes. +#[inline] +pub fn size_of<T>() -> uint { + unsafe { intrinsics::size_of::<T>() } +} + +/// Returns the size of the type that `_val` points to in bytes. +#[inline] +pub fn size_of_val<T>(_val: &T) -> uint { + size_of::<T>() +} + +/// Returns the size of a type in bytes, or 1 if the actual size is zero. +/// +/// Useful for building structures containing variable-length arrays. +#[inline] +pub fn nonzero_size_of<T>() -> uint { + match size_of::<T>() { + 0 => 1, + x => x + } +} + +/// Returns the size in bytes of the type of the value that `_val` points to. +#[inline] +pub fn nonzero_size_of_val<T>(_val: &T) -> uint { + nonzero_size_of::<T>() +} + +/// Returns the ABI-required minimum alignment of a type +/// +/// This is the alignment used for struct fields. It may be smaller +/// than the preferred alignment. +#[inline] +pub fn min_align_of<T>() -> uint { + unsafe { intrinsics::min_align_of::<T>() } +} + +/// Returns the ABI-required minimum alignment of the type of the value that +/// `_val` points to +#[inline] +pub fn min_align_of_val<T>(_val: &T) -> uint { + min_align_of::<T>() +} + +/// Returns the preferred alignment of a type +#[inline] +pub fn pref_align_of<T>() -> uint { + unsafe { intrinsics::pref_align_of::<T>() } +} + +/// Returns the preferred alignment of the type of the value that +/// `_val` points to +#[inline] +pub fn pref_align_of_val<T>(_val: &T) -> uint { + pref_align_of::<T>() +} + +/// Create a value initialized to zero. +/// +/// `init` is unsafe because it returns a zeroed-out datum, +/// which is unsafe unless T is Copy. +#[inline] +pub unsafe fn init<T>() -> T { + intrinsics::init() +} + +/// Create an uninitialized value. +#[inline] +pub unsafe fn uninit<T>() -> T { + intrinsics::uninit() +} + +/// Move a value to an uninitialized memory location. +/// +/// Drop glue is not run on the destination. +#[inline] +pub unsafe fn move_val_init<T>(dst: &mut T, src: T) { + intrinsics::move_val_init(dst, src) +} + +/// 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 = "little")] #[inline] pub fn to_le16(x: u16) -> u16 { x } + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + +/// 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) } } + + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + + +/// 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 } + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + +/// 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) } } + + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + +/// 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) } } + +/// 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 } + +/** + * Swap the values at two mutable locations of the same type, without + * deinitialising or copying either one. + */ +#[inline] +pub fn swap<T>(x: &mut T, y: &mut T) { + unsafe { + // Give ourselves some scratch space to work with + let mut t: T = uninit(); + + // Perform the swap, `&mut` pointers never alias + ptr::copy_nonoverlapping_memory(&mut t, &*x, 1); + ptr::copy_nonoverlapping_memory(x, &*y, 1); + ptr::copy_nonoverlapping_memory(y, &t, 1); + + // y and t now point to the same thing, but we need to completely forget `t` + // because it's no longer relevant. + cast::forget(t); + } +} + +/** + * Replace the value at a mutable location with a new one, returning the old + * value, without deinitialising or copying either one. + * + * This is primarily used for transferring and swapping ownership of a value + * in a mutable location. For example, this function allows consumption of + * one field of a struct by replacing it with another value. The normal approach + * doesn't always work: + * + * ```rust,ignore + * struct Buffer<T> { buf: Vec<T> } + * + * impl<T> Buffer<T> { + * fn get_and_reset(&mut self) -> Vec<T> { + * // error: cannot move out of dereference of `&mut`-pointer + * let buf = self.buf; + * self.buf = Vec::new(); + * buf + * } + * } + * ``` + * + * Note that `T` does not necessarily implement `Clone`, so it can't even + * clone and reset `self.buf`. But `replace` can be used to disassociate + * the original value of `self.buf` from `self`, allowing it to be returned: + * + * ```rust + * # struct Buffer<T> { buf: Vec<T> } + * impl<T> Buffer<T> { + * fn get_and_reset(&mut self) -> Vec<T> { + * use std::mem::replace; + * replace(&mut self.buf, Vec::new()) + * } + * } + * ``` + */ +#[inline] +pub fn replace<T>(dest: &mut T, mut src: T) -> T { + swap(dest, &mut src); + src +} + +/// Disposes of a value. +#[inline] +pub fn drop<T>(_x: T) { } + +#[cfg(test)] +mod tests { + use mem::*; + use option::{Some,None}; + use str::StrSlice; + + #[test] + fn size_of_basic() { + assert_eq!(size_of::<u8>(), 1u); + assert_eq!(size_of::<u16>(), 2u); + assert_eq!(size_of::<u32>(), 4u); + assert_eq!(size_of::<u64>(), 8u); + } + + #[test] + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "arm")] + #[cfg(target_arch = "mips")] + fn size_of_32() { + assert_eq!(size_of::<uint>(), 4u); + assert_eq!(size_of::<*uint>(), 4u); + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn size_of_64() { + assert_eq!(size_of::<uint>(), 8u); + assert_eq!(size_of::<*uint>(), 8u); + } + + #[test] + fn size_of_val_basic() { + assert_eq!(size_of_val(&1u8), 1); + assert_eq!(size_of_val(&1u16), 2); + assert_eq!(size_of_val(&1u32), 4); + assert_eq!(size_of_val(&1u64), 8); + } + + #[test] + fn nonzero_size_of_basic() { + type Z = [i8, ..0]; + assert_eq!(size_of::<Z>(), 0u); + assert_eq!(nonzero_size_of::<Z>(), 1u); + assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>()); + } + + #[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::<u8>(), 1u); + assert_eq!(pref_align_of::<u16>(), 2u); + assert_eq!(pref_align_of::<u32>(), 4u); + } + + #[test] + #[cfg(target_arch = "x86")] + #[cfg(target_arch = "arm")] + #[cfg(target_arch = "mips")] + fn align_of_32() { + assert_eq!(pref_align_of::<uint>(), 4u); + assert_eq!(pref_align_of::<*uint>(), 4u); + } + + #[test] + #[cfg(target_arch = "x86_64")] + fn align_of_64() { + assert_eq!(pref_align_of::<uint>(), 8u); + assert_eq!(pref_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); + } + + #[test] + fn test_swap() { + let mut x = 31337; + let mut y = 42; + swap(&mut x, &mut y); + assert_eq!(x, 42); + assert_eq!(y, 31337); + } + + #[test] + fn test_replace() { + let mut x = Some("test".to_owned()); + let y = replace(&mut x, None); + assert!(x.is_none()); + assert!(y.is_some()); + } +} + +// FIXME #13642 (these benchmarks should be in another place) +/// Completely miscellaneous language-construct benchmarks. +#[cfg(test)] +mod bench { + extern crate test; + use self::test::Bencher; + use option::{Some,None}; + + // Static/dynamic method dispatch + + struct Struct { + field: int + } + + trait Trait { + fn method(&self) -> int; + } + + impl Trait for Struct { + fn method(&self) -> int { + self.field + } + } + + #[bench] + fn trait_vtable_method_call(b: &mut Bencher) { + let s = Struct { field: 10 }; + let t = &s as &Trait; + b.iter(|| { + t.method() + }); + } + + #[bench] + fn trait_static_method_call(b: &mut Bencher) { + let s = Struct { field: 10 }; + b.iter(|| { + s.method() + }); + } + + // Overhead of various match forms + + #[bench] + fn match_option_some(b: &mut Bencher) { + let x = Some(10); + b.iter(|| { + match x { + Some(y) => y, + None => 11 + } + }); + } + + #[bench] + fn match_vec_pattern(b: &mut Bencher) { + let x = [1,2,3,4,5,6]; + b.iter(|| { + match x { + [1,2,3,..] => 10, + _ => 11 + } + }); + } +} |
