]> git.lizzy.rs Git - rust.git/blob - src/libstd/ptr.rs
dfd11f9227d413e5b37725b91a34e54d024f3eea
[rust.git] / src / libstd / ptr.rs
1 // Copyright 2012-2013 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 //! Unsafe pointer utility functions
12
13 use cast;
14 use clone::Clone;
15 use iterator::{range, Iterator};
16 use option::{Option, Some, None};
17 use unstable::intrinsics;
18 use util::swap;
19
20 #[cfg(not(test))] use ops::{Add,Sub};
21 #[cfg(not(test))] use num::Int;
22
23 #[cfg(not(test))] use cmp::{Eq, Ord};
24
25 /// Calculate the offset from a pointer
26 #[inline]
27 pub fn offset<T>(ptr: *T, count: int) -> *T {
28     unsafe { intrinsics::offset(ptr, count) }
29 }
30
31 /// Calculate the offset from a const pointer
32 #[inline]
33 pub fn const_offset<T>(ptr: *const T, count: int) -> *const T {
34     unsafe { intrinsics::offset(ptr as *T, count) }
35 }
36
37 /// Calculate the offset from a mut pointer
38 #[inline]
39 pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
40     unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
41 }
42
43 /// Return the offset of the first null pointer in `buf`.
44 #[inline]
45 pub unsafe fn buf_len<T>(buf: **T) -> uint {
46     position(buf, |i| *i == null())
47 }
48
49 impl<T> Clone for *T {
50     fn clone(&self) -> *T {
51         *self
52     }
53 }
54
55 /// Return the first offset `i` such that `f(buf[i]) == true`.
56 #[inline]
57 pub unsafe fn position<T>(buf: *T, f: &fn(&T) -> bool) -> uint {
58     let mut i = 0;
59     loop {
60         if f(&(*offset(buf, i as int))) { return i; }
61         else { i += 1; }
62     }
63 }
64
65 /// Create an unsafe null pointer
66 #[inline]
67 pub fn null<T>() -> *T { 0 as *T }
68
69 /// Create an unsafe mutable null pointer
70 #[inline]
71 pub fn mut_null<T>() -> *mut T { 0 as *mut T }
72
73 /// Returns true if the pointer is equal to the null pointer.
74 #[inline]
75 pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
76
77 /// Returns true if the pointer is not equal to the null pointer.
78 #[inline]
79 pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
80
81 /**
82  * Copies data from one location to another.
83  *
84  * Copies `count` elements (not bytes) from `src` to `dst`. The source
85  * and destination may overlap.
86  */
87 #[inline]
88 #[cfg(target_word_size = "32")]
89 pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
90     intrinsics::memmove32(dst, src as *T, count as u32);
91 }
92
93 /**
94  * Copies data from one location to another.
95  *
96  * Copies `count` elements (not bytes) from `src` to `dst`. The source
97  * and destination may overlap.
98  */
99 #[inline]
100 #[cfg(target_word_size = "64")]
101 pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
102     intrinsics::memmove64(dst, src as *T, count as u64);
103 }
104
105 /**
106  * Copies data from one location to another.
107  *
108  * Copies `count` elements (not bytes) from `src` to `dst`. The source
109  * and destination may *not* overlap.
110  */
111 #[inline]
112 #[cfg(target_word_size = "32")]
113 pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
114     intrinsics::memcpy32(dst, src as *T, count as u32);
115 }
116
117 /**
118  * Copies data from one location to another.
119  *
120  * Copies `count` elements (not bytes) from `src` to `dst`. The source
121  * and destination may *not* overlap.
122  */
123 #[inline]
124 #[cfg(target_word_size = "64")]
125 pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
126     intrinsics::memcpy64(dst, src as *T, count as u64);
127 }
128
129 /**
130  * Invokes memset on the specified pointer, setting `count * size_of::<T>()`
131  * bytes of memory starting at `dst` to `c`.
132  */
133 #[inline]
134 #[cfg(target_word_size = "32")]
135 pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
136     intrinsics::memset32(dst, c, count as u32);
137 }
138
139 /**
140  * Invokes memset on the specified pointer, setting `count * size_of::<T>()`
141  * bytes of memory starting at `dst` to `c`.
142  */
143 #[inline]
144 #[cfg(target_word_size = "64")]
145 pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
146     intrinsics::memset64(dst, c, count as u64);
147 }
148
149 /**
150  * Zeroes out `count * size_of::<T>` bytes of memory at `dst`
151  */
152 #[inline]
153 pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
154     set_memory(dst, 0, count);
155 }
156
157 /**
158  * Swap the values at two mutable locations of the same type, without
159  * deinitialising or copying either one.
160  */
161 #[inline]
162 pub unsafe fn swap_ptr<T>(x: *mut T, y: *mut T) {
163     // Give ourselves some scratch space to work with
164     let mut tmp: T = intrinsics::uninit();
165     let t: *mut T = &mut tmp;
166
167     // Perform the swap
168     copy_nonoverlapping_memory(t, x, 1);
169     copy_memory(x, y, 1); // `x` and `y` may overlap
170     copy_nonoverlapping_memory(y, t, 1);
171
172     // y and t now point to the same thing, but we need to completely forget `tmp`
173     // because it's no longer relevant.
174     cast::forget(tmp);
175 }
176
177 /**
178  * Replace the value at a mutable location with a new one, returning the old
179  * value, without deinitialising or copying either one.
180  */
181 #[inline]
182 pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T {
183     swap(cast::transmute(dest), &mut src); // cannot overlap
184     src
185 }
186
187 /**
188  * Reads the value from `*src` and returns it. Does not copy `*src`.
189  */
190 #[inline(always)]
191 pub unsafe fn read_ptr<T>(src: *mut T) -> T {
192     let mut tmp: T = intrinsics::uninit();
193     copy_nonoverlapping_memory(&mut tmp, src, 1);
194     tmp
195 }
196
197 /**
198  * Reads the value from `*src` and nulls it out.
199  * This currently prevents destructors from executing.
200  */
201 #[inline(always)]
202 pub unsafe fn read_and_zero_ptr<T>(dest: *mut T) -> T {
203     // Copy the data out from `dest`:
204     let tmp = read_ptr(dest);
205
206     // Now zero out `dest`:
207     zero_memory(dest, 1);
208
209     tmp
210 }
211
212 /// Transform a region pointer - &T - to an unsafe pointer - *T.
213 #[inline]
214 pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
215     thing as *T
216 }
217
218 /// Transform a const region pointer - &const T - to a const unsafe pointer - *const T.
219 #[inline]
220 pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
221     thing as *const T
222 }
223
224 /// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T.
225 #[inline]
226 pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
227     thing as *mut T
228 }
229
230 /**
231   Given a **T (pointer to an array of pointers),
232   iterate through each *T, up to the provided `len`,
233   passing to the provided callback function
234
235   SAFETY NOTE: Pointer-arithmetic. Dragons be here.
236 */
237 pub unsafe fn array_each_with_len<T>(arr: **T, len: uint, cb: &fn(*T)) {
238     debug!("array_each_with_len: before iterate");
239     if (arr as uint == 0) {
240         fail!("ptr::array_each_with_len failure: arr input is null pointer");
241     }
242     //let start_ptr = *arr;
243     for e in range(0, len) {
244         let n = offset(arr, e as int);
245         cb(*n);
246     }
247     debug!("array_each_with_len: after iterate");
248 }
249
250 /**
251   Given a null-pointer-terminated **T (pointer to
252   an array of pointers), iterate through each *T,
253   passing to the provided callback function
254
255   SAFETY NOTE: This will only work with a null-terminated
256   pointer array. Barely less-dodgey Pointer Arithmetic.
257   Dragons be here.
258 */
259 pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
260     if (arr as uint == 0) {
261         fail!("ptr::array_each_with_len failure: arr input is null pointer");
262     }
263     let len = buf_len(arr);
264     debug!("array_each inferred len: %u",
265                     len);
266     array_each_with_len(arr, len, cb);
267 }
268
269 #[allow(missing_doc)]
270 pub trait RawPtr<T> {
271     fn is_null(&self) -> bool;
272     fn is_not_null(&self) -> bool;
273     unsafe fn to_option(&self) -> Option<&T>;
274     fn offset(&self, count: int) -> Self;
275 }
276
277 /// Extension methods for immutable pointers
278 impl<T> RawPtr<T> for *T {
279     /// Returns true if the pointer is equal to the null pointer.
280     #[inline]
281     fn is_null(&self) -> bool { is_null(*self) }
282
283     /// Returns true if the pointer is not equal to the null pointer.
284     #[inline]
285     fn is_not_null(&self) -> bool { is_not_null(*self) }
286
287     ///
288     /// Returns `None` if the pointer is null, or else returns the value wrapped
289     /// in `Some`.
290     ///
291     /// # Safety Notes
292     ///
293     /// While this method is useful for null-safety, it is important to note
294     /// that this is still an unsafe operation because the returned value could
295     /// be pointing to invalid memory.
296     ///
297     #[inline]
298     unsafe fn to_option(&self) -> Option<&T> {
299         if self.is_null() { None } else {
300             Some(cast::transmute(*self))
301         }
302     }
303
304     /// Calculates the offset from a pointer.
305     #[inline]
306     fn offset(&self, count: int) -> *T { offset(*self, count) }
307 }
308
309 /// Extension methods for mutable pointers
310 impl<T> RawPtr<T> for *mut T {
311     /// Returns true if the pointer is equal to the null pointer.
312     #[inline]
313     fn is_null(&self) -> bool { is_null(*self) }
314
315     /// Returns true if the pointer is not equal to the null pointer.
316     #[inline]
317     fn is_not_null(&self) -> bool { is_not_null(*self) }
318
319     ///
320     /// Returns `None` if the pointer is null, or else returns the value wrapped
321     /// in `Some`.
322     ///
323     /// # Safety Notes
324     ///
325     /// While this method is useful for null-safety, it is important to note
326     /// that this is still an unsafe operation because the returned value could
327     /// be pointing to invalid memory.
328     ///
329     #[inline]
330     unsafe fn to_option(&self) -> Option<&T> {
331         if self.is_null() { None } else {
332             Some(cast::transmute(*self))
333         }
334     }
335
336     /// Calculates the offset from a mutable pointer.
337     #[inline]
338     fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
339 }
340
341 // Equality for pointers
342 #[cfg(not(test))]
343 impl<T> Eq for *const T {
344     #[inline]
345     fn eq(&self, other: &*const T) -> bool {
346         (*self as uint) == (*other as uint)
347     }
348     #[inline]
349     fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
350 }
351
352 // Comparison for pointers
353 #[cfg(not(test))]
354 impl<T> Ord for *const T {
355     #[inline]
356     fn lt(&self, other: &*const T) -> bool {
357         (*self as uint) < (*other as uint)
358     }
359     #[inline]
360     fn le(&self, other: &*const T) -> bool {
361         (*self as uint) <= (*other as uint)
362     }
363     #[inline]
364     fn ge(&self, other: &*const T) -> bool {
365         (*self as uint) >= (*other as uint)
366     }
367     #[inline]
368     fn gt(&self, other: &*const T) -> bool {
369         (*self as uint) > (*other as uint)
370     }
371 }
372
373 #[cfg(not(test))]
374 impl<T, I: Int> Add<I, *T> for *T {
375     /// Add an integer value to a pointer to get an offset pointer.
376     /// Is calculated according to the size of the type pointed to.
377     #[inline]
378     pub fn add(&self, rhs: &I) -> *T {
379         self.offset(rhs.to_int() as int)
380     }
381 }
382
383 #[cfg(not(test))]
384 impl<T, I: Int> Sub<I, *T> for *T {
385     /// Subtract an integer value from a pointer to get an offset pointer.
386     /// Is calculated according to the size of the type pointed to.
387     #[inline]
388     pub fn sub(&self, rhs: &I) -> *T {
389         self.offset(-rhs.to_int() as int)
390     }
391 }
392
393 #[cfg(not(test))]
394 impl<T, I: Int> Add<I, *mut T> for *mut T {
395     /// Add an integer value to a pointer to get an offset pointer.
396     /// Is calculated according to the size of the type pointed to.
397     #[inline]
398     pub fn add(&self, rhs: &I) -> *mut T {
399         self.offset(rhs.to_int() as int)
400     }
401 }
402
403 #[cfg(not(test))]
404 impl<T, I: Int> Sub<I, *mut T> for *mut T {
405     /// Subtract an integer value from a pointer to get an offset pointer.
406     /// Is calculated according to the size of the type pointed to.
407     #[inline]
408     pub fn sub(&self, rhs: &I) -> *mut T {
409         self.offset(-rhs.to_int() as int)
410     }
411 }
412
413 #[cfg(test)]
414 pub mod ptr_tests {
415     use super::*;
416     use prelude::*;
417
418     use cast;
419     use libc;
420     use str;
421     use vec;
422
423     #[test]
424     fn test() {
425         unsafe {
426             struct Pair {
427                 fst: int,
428                 snd: int
429             };
430             let mut p = Pair {fst: 10, snd: 20};
431             let pptr: *mut Pair = &mut p;
432             let iptr: *mut int = cast::transmute(pptr);
433             assert_eq!(*iptr, 10);
434             *iptr = 30;
435             assert_eq!(*iptr, 30);
436             assert_eq!(p.fst, 30);
437
438             *pptr = Pair {fst: 50, snd: 60};
439             assert_eq!(*iptr, 50);
440             assert_eq!(p.fst, 50);
441             assert_eq!(p.snd, 60);
442
443             let v0 = ~[32000u16, 32001u16, 32002u16];
444             let mut v1 = ~[0u16, 0u16, 0u16];
445
446             copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1),
447                         offset(vec::raw::to_ptr(v0), 1), 1);
448             assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
449             copy_memory(vec::raw::to_mut_ptr(v1),
450                         offset(vec::raw::to_ptr(v0), 2), 1);
451             assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
452                      v1[2] == 0u16));
453             copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 2),
454                         vec::raw::to_ptr(v0), 1u);
455             assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
456                      v1[2] == 32000u16));
457         }
458     }
459
460     #[test]
461     fn test_position() {
462         use libc::c_char;
463
464         let s = ~"hello";
465         unsafe {
466             assert!(2u == s.as_c_str(|p| position(p, |c| *c == 'l' as c_char)));
467             assert!(4u == s.as_c_str(|p| position(p, |c| *c == 'o' as c_char)));
468             assert!(5u == s.as_c_str(|p| position(p, |c| *c == 0 as c_char)));
469         }
470     }
471
472     #[test]
473     fn test_buf_len() {
474         let s0 = ~"hello";
475         let s1 = ~"there";
476         let s2 = ~"thing";
477         do s0.as_c_str |p0| {
478             do s1.as_c_str |p1| {
479                 do s2.as_c_str |p2| {
480                     let v = ~[p0, p1, p2, null()];
481                     do v.as_imm_buf |vp, len| {
482                         assert_eq!(unsafe { buf_len(vp) }, 3u);
483                         assert_eq!(len, 4u);
484                     }
485                 }
486             }
487         }
488     }
489
490     #[test]
491     fn test_is_null() {
492         let p: *int = null();
493         assert!(p.is_null());
494         assert!(!p.is_not_null());
495
496         let q = offset(p, 1);
497         assert!(!q.is_null());
498         assert!(q.is_not_null());
499
500         let mp: *mut int = mut_null();
501         assert!(mp.is_null());
502         assert!(!mp.is_not_null());
503
504         let mq = mp.offset(1);
505         assert!(!mq.is_null());
506         assert!(mq.is_not_null());
507     }
508
509     #[test]
510     fn test_to_option() {
511         unsafe {
512             let p: *int = null();
513             assert_eq!(p.to_option(), None);
514
515             let q: *int = &2;
516             assert_eq!(q.to_option().unwrap(), &2);
517
518             let p: *mut int = mut_null();
519             assert_eq!(p.to_option(), None);
520
521             let q: *mut int = &mut 2;
522             assert_eq!(q.to_option().unwrap(), &2);
523         }
524     }
525
526     #[test]
527     fn test_ptr_addition() {
528         use vec::raw::*;
529
530         unsafe {
531             let xs = ~[5, ..16];
532             let mut ptr = to_ptr(xs);
533             let end = ptr + 16;
534
535             while ptr < end {
536                 assert_eq!(*ptr, 5);
537                 ptr = ptr + 1u;
538             }
539
540             let mut xs_mut = xs.clone();
541             let mut m_ptr = to_mut_ptr(xs_mut);
542             let m_end = m_ptr + 16i16;
543
544             while m_ptr < m_end {
545                 *m_ptr += 5;
546                 m_ptr = m_ptr + 1u8;
547             }
548
549             assert_eq!(xs_mut, ~[10, ..16]);
550         }
551     }
552
553     #[test]
554     fn test_ptr_subtraction() {
555         use vec::raw::*;
556
557         unsafe {
558             let xs = ~[0,1,2,3,4,5,6,7,8,9];
559             let mut idx = 9i8;
560             let ptr = to_ptr(xs);
561
562             while idx >= 0i8 {
563                 assert_eq!(*(ptr + idx), idx as int);
564                 idx = idx - 1i8;
565             }
566
567             let mut xs_mut = xs.clone();
568             let m_start = to_mut_ptr(xs_mut);
569             let mut m_ptr = m_start + 9u32;
570
571             while m_ptr >= m_start {
572                 *m_ptr += *m_ptr;
573                 m_ptr = m_ptr - 1i8;
574             }
575
576             assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
577         }
578     }
579
580     #[test]
581     fn test_ptr_array_each_with_len() {
582         unsafe {
583             let one = ~"oneOne";
584             let two = ~"twoTwo";
585             let three = ~"threeThree";
586             let arr: ~[*i8] = ~[
587                 ::cast::transmute(&one[0]),
588                 ::cast::transmute(&two[0]),
589                 ::cast::transmute(&three[0]),
590             ];
591             let expected_arr = [
592                 one, two, three
593             ];
594             let arr_ptr = &arr[0];
595             let mut ctr = 0;
596             let mut iteration_count = 0;
597             array_each_with_len(arr_ptr, arr.len(),
598                                 |e| {
599                                          let actual = str::raw::from_c_str(e);
600                                          let expected = expected_arr[ctr].clone();
601                                          debug!(
602                                              "test_ptr_array_each e: %s, a: %s",
603                                              expected, actual);
604                                          assert_eq!(actual, expected);
605                                          ctr += 1;
606                                          iteration_count += 1;
607                                      });
608             assert_eq!(iteration_count, 3u);
609         }
610     }
611     #[test]
612     fn test_ptr_array_each() {
613         unsafe {
614             let one = ~"oneOne";
615             let two = ~"twoTwo";
616             let three = ~"threeThree";
617             let arr: ~[*i8] = ~[
618                 ::cast::transmute(&one[0]),
619                 ::cast::transmute(&two[0]),
620                 ::cast::transmute(&three[0]),
621                 // fake a null terminator
622                 0 as *i8
623             ];
624             let expected_arr = [
625                 one, two, three
626             ];
627             let arr_ptr = &arr[0];
628             let mut ctr = 0;
629             let mut iteration_count = 0;
630             array_each(arr_ptr, |e| {
631                 let actual = str::raw::from_c_str(e);
632                 let expected = expected_arr[ctr].clone();
633                 debug!(
634                     "test_ptr_array_each e: %s, a: %s",
635                     expected, actual);
636                 assert_eq!(actual, expected);
637                 ctr += 1;
638                 iteration_count += 1;
639             });
640             assert_eq!(iteration_count, 3);
641         }
642     }
643     #[test]
644     #[should_fail]
645     #[ignore(cfg(windows))]
646     fn test_ptr_array_each_with_len_null_ptr() {
647         unsafe {
648             array_each_with_len(0 as **libc::c_char, 1, |e| {
649                 str::raw::from_c_str(e);
650             });
651         }
652     }
653     #[test]
654     #[should_fail]
655     #[ignore(cfg(windows))]
656     fn test_ptr_array_each_null_ptr() {
657         unsafe {
658             array_each(0 as **libc::c_char, |e| {
659                 str::raw::from_c_str(e);
660             });
661         }
662     }
663
664     #[test]
665     fn test_set_memory() {
666         let mut xs = [0u8, ..20];
667         let ptr = vec::raw::to_mut_ptr(xs);
668         unsafe { set_memory(ptr, 5u8, xs.len()); }
669         assert_eq!(xs, [5u8, ..20]);
670     }
671 }