]> git.lizzy.rs Git - rust.git/blob - src/libstd/ptr.rs
add an intrinsic for inbounds GEP
[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     #[cfg(not(stage0))]
276     unsafe fn offset_inbounds(self, count: int) -> Self;
277 }
278
279 /// Extension methods for immutable pointers
280 impl<T> RawPtr<T> for *T {
281     /// Returns true if the pointer is equal to the null pointer.
282     #[inline]
283     fn is_null(&self) -> bool { is_null(*self) }
284
285     /// Returns true if the pointer is not equal to the null pointer.
286     #[inline]
287     fn is_not_null(&self) -> bool { is_not_null(*self) }
288
289     ///
290     /// Returns `None` if the pointer is null, or else returns the value wrapped
291     /// in `Some`.
292     ///
293     /// # Safety Notes
294     ///
295     /// While this method is useful for null-safety, it is important to note
296     /// that this is still an unsafe operation because the returned value could
297     /// be pointing to invalid memory.
298     ///
299     #[inline]
300     unsafe fn to_option(&self) -> Option<&T> {
301         if self.is_null() { None } else {
302             Some(cast::transmute(*self))
303         }
304     }
305
306     /// Calculates the offset from a pointer.
307     #[inline]
308     fn offset(&self, count: int) -> *T { offset(*self, count) }
309
310     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
311     /// the object, or one-byte-past-the-end.
312     #[inline]
313     #[cfg(not(stage0))]
314     unsafe fn offset_inbounds(self, count: int) -> *T {
315         intrinsics::offset_inbounds(self, count)
316     }
317 }
318
319 /// Extension methods for mutable pointers
320 impl<T> RawPtr<T> for *mut T {
321     /// Returns true if the pointer is equal to the null pointer.
322     #[inline]
323     fn is_null(&self) -> bool { is_null(*self) }
324
325     /// Returns true if the pointer is not equal to the null pointer.
326     #[inline]
327     fn is_not_null(&self) -> bool { is_not_null(*self) }
328
329     ///
330     /// Returns `None` if the pointer is null, or else returns the value wrapped
331     /// in `Some`.
332     ///
333     /// # Safety Notes
334     ///
335     /// While this method is useful for null-safety, it is important to note
336     /// that this is still an unsafe operation because the returned value could
337     /// be pointing to invalid memory.
338     ///
339     #[inline]
340     unsafe fn to_option(&self) -> Option<&T> {
341         if self.is_null() { None } else {
342             Some(cast::transmute(*self))
343         }
344     }
345
346     /// Calculates the offset from a mutable pointer.
347     #[inline]
348     fn offset(&self, count: int) -> *mut T { mut_offset(*self, count) }
349
350     /// Calculates the offset from a pointer. The offset *must* be in-bounds of
351     /// the object, or one-byte-past-the-end. An arithmetic overflow is also
352     /// undefined behaviour.
353     ///
354     /// This method should be preferred over `offset` when the guarantee can be
355     /// satisfied, to enable better optimization.
356     #[inline]
357     #[cfg(not(stage0))]
358     unsafe fn offset_inbounds(self, count: int) -> *mut T {
359         intrinsics::offset_inbounds(self as *T, count) as *mut T
360     }
361 }
362
363 // Equality for pointers
364 #[cfg(not(test))]
365 impl<T> Eq for *const T {
366     #[inline]
367     fn eq(&self, other: &*const T) -> bool {
368         (*self as uint) == (*other as uint)
369     }
370     #[inline]
371     fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
372 }
373
374 // Comparison for pointers
375 #[cfg(not(test))]
376 impl<T> Ord for *const T {
377     #[inline]
378     fn lt(&self, other: &*const T) -> bool {
379         (*self as uint) < (*other as uint)
380     }
381     #[inline]
382     fn le(&self, other: &*const T) -> bool {
383         (*self as uint) <= (*other as uint)
384     }
385     #[inline]
386     fn ge(&self, other: &*const T) -> bool {
387         (*self as uint) >= (*other as uint)
388     }
389     #[inline]
390     fn gt(&self, other: &*const T) -> bool {
391         (*self as uint) > (*other as uint)
392     }
393 }
394
395 #[cfg(not(test))]
396 impl<T, I: Int> Add<I, *T> for *T {
397     /// Add an integer value to a pointer to get an offset pointer.
398     /// Is calculated according to the size of the type pointed to.
399     #[inline]
400     pub fn add(&self, rhs: &I) -> *T {
401         self.offset(rhs.to_int() as int)
402     }
403 }
404
405 #[cfg(not(test))]
406 impl<T, I: Int> Sub<I, *T> for *T {
407     /// Subtract an integer value from a pointer to get an offset pointer.
408     /// Is calculated according to the size of the type pointed to.
409     #[inline]
410     pub fn sub(&self, rhs: &I) -> *T {
411         self.offset(-rhs.to_int() as int)
412     }
413 }
414
415 #[cfg(not(test))]
416 impl<T, I: Int> Add<I, *mut T> for *mut T {
417     /// Add an integer value to a pointer to get an offset pointer.
418     /// Is calculated according to the size of the type pointed to.
419     #[inline]
420     pub fn add(&self, rhs: &I) -> *mut T {
421         self.offset(rhs.to_int() as int)
422     }
423 }
424
425 #[cfg(not(test))]
426 impl<T, I: Int> Sub<I, *mut T> for *mut T {
427     /// Subtract an integer value from a pointer to get an offset pointer.
428     /// Is calculated according to the size of the type pointed to.
429     #[inline]
430     pub fn sub(&self, rhs: &I) -> *mut T {
431         self.offset(-rhs.to_int() as int)
432     }
433 }
434
435 #[cfg(test)]
436 pub mod ptr_tests {
437     use super::*;
438     use prelude::*;
439
440     use cast;
441     use libc;
442     use str;
443     use vec;
444
445     #[test]
446     fn test() {
447         unsafe {
448             struct Pair {
449                 fst: int,
450                 snd: int
451             };
452             let mut p = Pair {fst: 10, snd: 20};
453             let pptr: *mut Pair = &mut p;
454             let iptr: *mut int = cast::transmute(pptr);
455             assert_eq!(*iptr, 10);
456             *iptr = 30;
457             assert_eq!(*iptr, 30);
458             assert_eq!(p.fst, 30);
459
460             *pptr = Pair {fst: 50, snd: 60};
461             assert_eq!(*iptr, 50);
462             assert_eq!(p.fst, 50);
463             assert_eq!(p.snd, 60);
464
465             let v0 = ~[32000u16, 32001u16, 32002u16];
466             let mut v1 = ~[0u16, 0u16, 0u16];
467
468             copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 1),
469                         offset(vec::raw::to_ptr(v0), 1), 1);
470             assert!((v1[0] == 0u16 && v1[1] == 32001u16 && v1[2] == 0u16));
471             copy_memory(vec::raw::to_mut_ptr(v1),
472                         offset(vec::raw::to_ptr(v0), 2), 1);
473             assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
474                      v1[2] == 0u16));
475             copy_memory(mut_offset(vec::raw::to_mut_ptr(v1), 2),
476                         vec::raw::to_ptr(v0), 1u);
477             assert!((v1[0] == 32002u16 && v1[1] == 32001u16 &&
478                      v1[2] == 32000u16));
479         }
480     }
481
482     #[test]
483     fn test_position() {
484         use libc::c_char;
485
486         let s = ~"hello";
487         unsafe {
488             assert!(2u == s.as_c_str(|p| position(p, |c| *c == 'l' as c_char)));
489             assert!(4u == s.as_c_str(|p| position(p, |c| *c == 'o' as c_char)));
490             assert!(5u == s.as_c_str(|p| position(p, |c| *c == 0 as c_char)));
491         }
492     }
493
494     #[test]
495     fn test_buf_len() {
496         let s0 = ~"hello";
497         let s1 = ~"there";
498         let s2 = ~"thing";
499         do s0.as_c_str |p0| {
500             do s1.as_c_str |p1| {
501                 do s2.as_c_str |p2| {
502                     let v = ~[p0, p1, p2, null()];
503                     do v.as_imm_buf |vp, len| {
504                         assert_eq!(unsafe { buf_len(vp) }, 3u);
505                         assert_eq!(len, 4u);
506                     }
507                 }
508             }
509         }
510     }
511
512     #[test]
513     fn test_is_null() {
514         let p: *int = null();
515         assert!(p.is_null());
516         assert!(!p.is_not_null());
517
518         let q = offset(p, 1);
519         assert!(!q.is_null());
520         assert!(q.is_not_null());
521
522         let mp: *mut int = mut_null();
523         assert!(mp.is_null());
524         assert!(!mp.is_not_null());
525
526         let mq = mp.offset(1);
527         assert!(!mq.is_null());
528         assert!(mq.is_not_null());
529     }
530
531     #[test]
532     fn test_to_option() {
533         unsafe {
534             let p: *int = null();
535             assert_eq!(p.to_option(), None);
536
537             let q: *int = &2;
538             assert_eq!(q.to_option().unwrap(), &2);
539
540             let p: *mut int = mut_null();
541             assert_eq!(p.to_option(), None);
542
543             let q: *mut int = &mut 2;
544             assert_eq!(q.to_option().unwrap(), &2);
545         }
546     }
547
548     #[test]
549     fn test_ptr_addition() {
550         use vec::raw::*;
551
552         unsafe {
553             let xs = ~[5, ..16];
554             let mut ptr = to_ptr(xs);
555             let end = ptr + 16;
556
557             while ptr < end {
558                 assert_eq!(*ptr, 5);
559                 ptr = ptr + 1u;
560             }
561
562             let mut xs_mut = xs.clone();
563             let mut m_ptr = to_mut_ptr(xs_mut);
564             let m_end = m_ptr + 16i16;
565
566             while m_ptr < m_end {
567                 *m_ptr += 5;
568                 m_ptr = m_ptr + 1u8;
569             }
570
571             assert_eq!(xs_mut, ~[10, ..16]);
572         }
573     }
574
575     #[test]
576     fn test_ptr_subtraction() {
577         use vec::raw::*;
578
579         unsafe {
580             let xs = ~[0,1,2,3,4,5,6,7,8,9];
581             let mut idx = 9i8;
582             let ptr = to_ptr(xs);
583
584             while idx >= 0i8 {
585                 assert_eq!(*(ptr + idx), idx as int);
586                 idx = idx - 1i8;
587             }
588
589             let mut xs_mut = xs.clone();
590             let m_start = to_mut_ptr(xs_mut);
591             let mut m_ptr = m_start + 9u32;
592
593             while m_ptr >= m_start {
594                 *m_ptr += *m_ptr;
595                 m_ptr = m_ptr - 1i8;
596             }
597
598             assert_eq!(xs_mut, ~[0,2,4,6,8,10,12,14,16,18]);
599         }
600     }
601
602     #[test]
603     fn test_ptr_array_each_with_len() {
604         unsafe {
605             let one = ~"oneOne";
606             let two = ~"twoTwo";
607             let three = ~"threeThree";
608             let arr: ~[*i8] = ~[
609                 ::cast::transmute(&one[0]),
610                 ::cast::transmute(&two[0]),
611                 ::cast::transmute(&three[0]),
612             ];
613             let expected_arr = [
614                 one, two, three
615             ];
616             let arr_ptr = &arr[0];
617             let mut ctr = 0;
618             let mut iteration_count = 0;
619             array_each_with_len(arr_ptr, arr.len(),
620                                 |e| {
621                                          let actual = str::raw::from_c_str(e);
622                                          let expected = expected_arr[ctr].clone();
623                                          debug!(
624                                              "test_ptr_array_each e: %s, a: %s",
625                                              expected, actual);
626                                          assert_eq!(actual, expected);
627                                          ctr += 1;
628                                          iteration_count += 1;
629                                      });
630             assert_eq!(iteration_count, 3u);
631         }
632     }
633     #[test]
634     fn test_ptr_array_each() {
635         unsafe {
636             let one = ~"oneOne";
637             let two = ~"twoTwo";
638             let three = ~"threeThree";
639             let arr: ~[*i8] = ~[
640                 ::cast::transmute(&one[0]),
641                 ::cast::transmute(&two[0]),
642                 ::cast::transmute(&three[0]),
643                 // fake a null terminator
644                 0 as *i8
645             ];
646             let expected_arr = [
647                 one, two, three
648             ];
649             let arr_ptr = &arr[0];
650             let mut ctr = 0;
651             let mut iteration_count = 0;
652             array_each(arr_ptr, |e| {
653                 let actual = str::raw::from_c_str(e);
654                 let expected = expected_arr[ctr].clone();
655                 debug!(
656                     "test_ptr_array_each e: %s, a: %s",
657                     expected, actual);
658                 assert_eq!(actual, expected);
659                 ctr += 1;
660                 iteration_count += 1;
661             });
662             assert_eq!(iteration_count, 3);
663         }
664     }
665     #[test]
666     #[should_fail]
667     #[ignore(cfg(windows))]
668     fn test_ptr_array_each_with_len_null_ptr() {
669         unsafe {
670             array_each_with_len(0 as **libc::c_char, 1, |e| {
671                 str::raw::from_c_str(e);
672             });
673         }
674     }
675     #[test]
676     #[should_fail]
677     #[ignore(cfg(windows))]
678     fn test_ptr_array_each_null_ptr() {
679         unsafe {
680             array_each(0 as **libc::c_char, |e| {
681                 str::raw::from_c_str(e);
682             });
683         }
684     }
685
686     #[test]
687     fn test_set_memory() {
688         let mut xs = [0u8, ..20];
689         let ptr = vec::raw::to_mut_ptr(xs);
690         unsafe { set_memory(ptr, 5u8, xs.len()); }
691         assert_eq!(xs, [5u8, ..20]);
692     }
693 }