]> git.lizzy.rs Git - rust.git/blob - src/libstd/mem.rs
Convert most code to new inner attribute syntax.
[rust.git] / src / libstd / mem.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Basic functions for dealing with memory
12 //!
13 //! This module contains functions for querying the size and alignment of
14 //! types, initializing and manipulating memory.
15
16 #![allow(missing_doc)] // FIXME
17
18 use cast;
19 use ptr;
20 use intrinsics;
21 use intrinsics::{bswap16, bswap32, bswap64};
22
23 /// Returns the size of a type in bytes.
24 #[inline]
25 pub fn size_of<T>() -> uint {
26     unsafe { intrinsics::size_of::<T>() }
27 }
28
29 /// Returns the size of the type that `_val` points to in bytes.
30 #[inline]
31 pub fn size_of_val<T>(_val: &T) -> uint {
32     size_of::<T>()
33 }
34
35 /// Returns the size of a type in bytes, or 1 if the actual size is zero.
36 ///
37 /// Useful for building structures containing variable-length arrays.
38 #[inline]
39 pub fn nonzero_size_of<T>() -> uint {
40     let s = size_of::<T>();
41     if s == 0 { 1 } else { s }
42 }
43
44 /// Returns the size in bytes of the type of the value that `_val` points to.
45 #[inline]
46 pub fn nonzero_size_of_val<T>(_val: &T) -> uint {
47     nonzero_size_of::<T>()
48 }
49
50 /// Returns the ABI-required minimum alignment of a type
51 ///
52 /// This is the alignment used for struct fields. It may be smaller
53 /// than the preferred alignment.
54 #[inline]
55 pub fn min_align_of<T>() -> uint {
56     unsafe { intrinsics::min_align_of::<T>() }
57 }
58
59 /// Returns the ABI-required minimum alignment of the type of the value that
60 /// `_val` points to
61 #[inline]
62 pub fn min_align_of_val<T>(_val: &T) -> uint {
63     min_align_of::<T>()
64 }
65
66 /// Returns the preferred alignment of a type
67 #[inline]
68 pub fn pref_align_of<T>() -> uint {
69     unsafe { intrinsics::pref_align_of::<T>() }
70 }
71
72 /// Returns the preferred alignment of the type of the value that
73 /// `_val` points to
74 #[inline]
75 pub fn pref_align_of_val<T>(_val: &T) -> uint {
76     pref_align_of::<T>()
77 }
78
79 /// Create a value initialized to zero.
80 ///
81 /// `init` is unsafe because it returns a zeroed-out datum,
82 /// which is unsafe unless T is Copy.
83 #[inline]
84 pub unsafe fn init<T>() -> T {
85     intrinsics::init()
86 }
87
88 /// Create an uninitialized value.
89 #[inline]
90 pub unsafe fn uninit<T>() -> T {
91     intrinsics::uninit()
92 }
93
94 /// Move a value to an uninitialized memory location.
95 ///
96 /// Drop glue is not run on the destination.
97 #[inline]
98 pub unsafe fn move_val_init<T>(dst: &mut T, src: T) {
99     intrinsics::move_val_init(dst, src)
100 }
101
102 /// Convert an i16 to little endian from the target's endianness.
103 ///
104 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
105 #[cfg(target_endian = "little")] #[inline] pub fn to_le16(x: i16) -> i16 { x }
106
107 /// Convert an i16 to little endian from the target's endianness.
108 ///
109 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
110 #[cfg(target_endian = "big")]    #[inline] pub fn to_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
111
112 /// Convert an i32 to little endian from the target's endianness.
113 ///
114 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
115 #[cfg(target_endian = "little")] #[inline] pub fn to_le32(x: i32) -> i32 { x }
116
117 /// Convert an i32 to little endian from the target's endianness.
118 ///
119 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
120 #[cfg(target_endian = "big")]    #[inline] pub fn to_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
121
122 /// Convert an i64 to little endian from the target's endianness.
123 ///
124 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
125 #[cfg(target_endian = "little")] #[inline] pub fn to_le64(x: i64) -> i64 { x }
126
127 /// Convert an i64 to little endian from the target's endianness.
128 ///
129 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
130 #[cfg(target_endian = "big")]    #[inline] pub fn to_le64(x: i64) -> i64 { unsafe { bswap64(x) } }
131
132
133 /// Convert an i16 to big endian from the target's endianness.
134 ///
135 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
136 #[cfg(target_endian = "little")] #[inline] pub fn to_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
137
138 /// Convert an i16 to big endian from the target's endianness.
139 ///
140 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
141 #[cfg(target_endian = "big")]    #[inline] pub fn to_be16(x: i16) -> i16 { x }
142
143 /// Convert an i32 to big endian from the target's endianness.
144 ///
145 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
146 #[cfg(target_endian = "little")] #[inline] pub fn to_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
147
148 /// Convert an i32 to big endian from the target's endianness.
149 ///
150 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
151 #[cfg(target_endian = "big")]    #[inline] pub fn to_be32(x: i32) -> i32 { x }
152
153 /// Convert an i64 to big endian from the target's endianness.
154 ///
155 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
156 #[cfg(target_endian = "little")] #[inline] pub fn to_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
157
158 /// Convert an i64 to big endian from the target's endianness.
159 ///
160 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
161 #[cfg(target_endian = "big")]    #[inline] pub fn to_be64(x: i64) -> i64 { x }
162
163
164 /// Convert an i16 from little endian to the target's endianness.
165 ///
166 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
167 #[cfg(target_endian = "little")] #[inline] pub fn from_le16(x: i16) -> i16 { x }
168
169 /// Convert an i16 from little endian to the target's endianness.
170 ///
171 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
172 #[cfg(target_endian = "big")]    #[inline] pub fn from_le16(x: i16) -> i16 { unsafe { bswap16(x) } }
173
174 /// Convert an i32 from little endian to the target's endianness.
175 ///
176 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
177 #[cfg(target_endian = "little")] #[inline] pub fn from_le32(x: i32) -> i32 { x }
178
179 /// Convert an i32 from little endian to the target's endianness.
180 ///
181 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
182 #[cfg(target_endian = "big")]    #[inline] pub fn from_le32(x: i32) -> i32 { unsafe { bswap32(x) } }
183
184 /// Convert an i64 from little endian to the target's endianness.
185 ///
186 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
187 #[cfg(target_endian = "little")] #[inline] pub fn from_le64(x: i64) -> i64 { x }
188
189 /// Convert an i64 from little endian to the target's endianness.
190 ///
191 /// On little endian, this is a no-op.  On big endian, the bytes are swapped.
192 #[cfg(target_endian = "big")]    #[inline] pub fn from_le64(x: i64) -> i64 { unsafe { bswap64(x) } }
193
194
195 /// Convert an i16 from big endian to the target's endianness.
196 ///
197 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
198 #[cfg(target_endian = "little")] #[inline] pub fn from_be16(x: i16) -> i16 { unsafe { bswap16(x) } }
199
200 /// Convert an i16 from big endian to the target's endianness.
201 ///
202 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
203 #[cfg(target_endian = "big")]    #[inline] pub fn from_be16(x: i16) -> i16 { x }
204
205 /// Convert an i32 from big endian to the target's endianness.
206 ///
207 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
208 #[cfg(target_endian = "little")] #[inline] pub fn from_be32(x: i32) -> i32 { unsafe { bswap32(x) } }
209
210 /// Convert an i32 from big endian to the target's endianness.
211 ///
212 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
213 #[cfg(target_endian = "big")]    #[inline] pub fn from_be32(x: i32) -> i32 { x }
214
215 /// Convert an i64 from big endian to the target's endianness.
216 ///
217 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
218 #[cfg(target_endian = "little")] #[inline] pub fn from_be64(x: i64) -> i64 { unsafe { bswap64(x) } }
219
220 /// Convert an i64 from big endian to the target's endianness.
221 ///
222 /// On big endian, this is a no-op.  On little endian, the bytes are swapped.
223 #[cfg(target_endian = "big")]    #[inline] pub fn from_be64(x: i64) -> i64 { x }
224
225
226 /**
227  * Swap the values at two mutable locations of the same type, without
228  * deinitialising or copying either one.
229  */
230 #[inline]
231 pub fn swap<T>(x: &mut T, y: &mut T) {
232     unsafe {
233         // Give ourselves some scratch space to work with
234         let mut t: T = uninit();
235
236         // Perform the swap, `&mut` pointers never alias
237         ptr::copy_nonoverlapping_memory(&mut t, &*x, 1);
238         ptr::copy_nonoverlapping_memory(x, &*y, 1);
239         ptr::copy_nonoverlapping_memory(y, &t, 1);
240
241         // y and t now point to the same thing, but we need to completely forget `tmp`
242         // because it's no longer relevant.
243         cast::forget(t);
244     }
245 }
246
247 /**
248  * Replace the value at a mutable location with a new one, returning the old
249  * value, without deinitialising or copying either one.
250  */
251 #[inline]
252 pub fn replace<T>(dest: &mut T, mut src: T) -> T {
253     swap(dest, &mut src);
254     src
255 }
256
257 /// Disposes of a value.
258 #[inline]
259 pub fn drop<T>(_x: T) { }
260
261 #[cfg(test)]
262 mod tests {
263     use mem::*;
264     use option::{Some,None};
265
266     #[test]
267     fn size_of_basic() {
268         assert_eq!(size_of::<u8>(), 1u);
269         assert_eq!(size_of::<u16>(), 2u);
270         assert_eq!(size_of::<u32>(), 4u);
271         assert_eq!(size_of::<u64>(), 8u);
272     }
273
274     #[test]
275     #[cfg(target_arch = "x86")]
276     #[cfg(target_arch = "arm")]
277     #[cfg(target_arch = "mips")]
278     fn size_of_32() {
279         assert_eq!(size_of::<uint>(), 4u);
280         assert_eq!(size_of::<*uint>(), 4u);
281     }
282
283     #[test]
284     #[cfg(target_arch = "x86_64")]
285     fn size_of_64() {
286         assert_eq!(size_of::<uint>(), 8u);
287         assert_eq!(size_of::<*uint>(), 8u);
288     }
289
290     #[test]
291     fn size_of_val_basic() {
292         assert_eq!(size_of_val(&1u8), 1);
293         assert_eq!(size_of_val(&1u16), 2);
294         assert_eq!(size_of_val(&1u32), 4);
295         assert_eq!(size_of_val(&1u64), 8);
296     }
297
298     #[test]
299     fn nonzero_size_of_basic() {
300         type Z = [i8, ..0];
301         assert_eq!(size_of::<Z>(), 0u);
302         assert_eq!(nonzero_size_of::<Z>(), 1u);
303         assert_eq!(nonzero_size_of::<uint>(), size_of::<uint>());
304     }
305
306     #[test]
307     fn nonzero_size_of_val_basic() {
308         let z = [0u8, ..0];
309         assert_eq!(size_of_val(&z), 0u);
310         assert_eq!(nonzero_size_of_val(&z), 1u);
311         assert_eq!(nonzero_size_of_val(&1u), size_of_val(&1u));
312     }
313
314     #[test]
315     fn align_of_basic() {
316         assert_eq!(pref_align_of::<u8>(), 1u);
317         assert_eq!(pref_align_of::<u16>(), 2u);
318         assert_eq!(pref_align_of::<u32>(), 4u);
319     }
320
321     #[test]
322     #[cfg(target_arch = "x86")]
323     #[cfg(target_arch = "arm")]
324     #[cfg(target_arch = "mips")]
325     fn align_of_32() {
326         assert_eq!(pref_align_of::<uint>(), 4u);
327         assert_eq!(pref_align_of::<*uint>(), 4u);
328     }
329
330     #[test]
331     #[cfg(target_arch = "x86_64")]
332     fn align_of_64() {
333         assert_eq!(pref_align_of::<uint>(), 8u);
334         assert_eq!(pref_align_of::<*uint>(), 8u);
335     }
336
337     #[test]
338     fn align_of_val_basic() {
339         assert_eq!(pref_align_of_val(&1u8), 1u);
340         assert_eq!(pref_align_of_val(&1u16), 2u);
341         assert_eq!(pref_align_of_val(&1u32), 4u);
342     }
343
344     #[test]
345     fn test_swap() {
346         let mut x = 31337;
347         let mut y = 42;
348         swap(&mut x, &mut y);
349         assert_eq!(x, 42);
350         assert_eq!(y, 31337);
351     }
352
353     #[test]
354     fn test_replace() {
355         let mut x = Some(~"test");
356         let y = replace(&mut x, None);
357         assert!(x.is_none());
358         assert!(y.is_some());
359     }
360 }
361
362 /// Completely miscellaneous language-construct benchmarks.
363 #[cfg(test)]
364 mod bench {
365     extern crate test;
366     use self::test::BenchHarness;
367     use option::{Some,None};
368
369     // Static/dynamic method dispatch
370
371     struct Struct {
372         field: int
373     }
374
375     trait Trait {
376         fn method(&self) -> int;
377     }
378
379     impl Trait for Struct {
380         fn method(&self) -> int {
381             self.field
382         }
383     }
384
385     #[bench]
386     fn trait_vtable_method_call(bh: &mut BenchHarness) {
387         let s = Struct { field: 10 };
388         let t = &s as &Trait;
389         bh.iter(|| {
390             t.method()
391         });
392     }
393
394     #[bench]
395     fn trait_static_method_call(bh: &mut BenchHarness) {
396         let s = Struct { field: 10 };
397         bh.iter(|| {
398             s.method()
399         });
400     }
401
402     // Overhead of various match forms
403
404     #[bench]
405     fn match_option_some(bh: &mut BenchHarness) {
406         let x = Some(10);
407         bh.iter(|| {
408             match x {
409                 Some(y) => y,
410                 None => 11
411             }
412         });
413     }
414
415     #[bench]
416     fn match_vec_pattern(bh: &mut BenchHarness) {
417         let x = [1,2,3,4,5,6];
418         bh.iter(|| {
419             match x {
420                 [1,2,3,..] => 10,
421                 _ => 11
422             }
423         });
424     }
425 }