update ptr intrinsics and rewrite vec routines to be more correct.
In particular, it is not valid to go around passing uninitialized or zero'd memory as arguments. Rust should generally be free to assume that the arguments it gets are valid input values, but the output of intrinsics::uninit() and intrinsics::init() are not (e.g., an @T is just null, leading to an error if we should try to increment the ref count).
This commit is contained in:
@@ -142,6 +142,30 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
|
|||||||
memset64(dst, c, count as u64);
|
memset64(dst, c, count as u64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeroes out `count` bytes of memory at `dst`
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(stage0))]
|
||||||
|
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
|
||||||
|
set_memory(dst, 0, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Zeroes out `count * size_of::<T>` bytes of memory at `dst`
|
||||||
|
*/
|
||||||
|
#[inline]
|
||||||
|
#[cfg(stage0)]
|
||||||
|
pub unsafe fn zero_memory<T>(dst: *mut T, count: uint) {
|
||||||
|
let mut count = count * sys::size_of::<T>();
|
||||||
|
let mut dst = dst as *mut u8;
|
||||||
|
while count > 0 {
|
||||||
|
*dst = 0;
|
||||||
|
dst = mut_offset(dst, 1);
|
||||||
|
count -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Swap the values at two mutable locations of the same type, without
|
* Swap the values at two mutable locations of the same type, without
|
||||||
* deinitialising or copying either one.
|
* deinitialising or copying either one.
|
||||||
@@ -172,6 +196,32 @@ pub unsafe fn replace_ptr<T>(dest: *mut T, mut src: T) -> T {
|
|||||||
src
|
src
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value from `*src` and returns it. Does not copy `*src`.
|
||||||
|
*/
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn read_ptr<T>(src: *mut T) -> T {
|
||||||
|
let mut tmp: T = intrinsics::uninit();
|
||||||
|
let t: *mut T = &mut tmp;
|
||||||
|
copy_memory(t, src, 1);
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads the value from `*src` and nulls it out.
|
||||||
|
* This currently prevents destructors from executing.
|
||||||
|
*/
|
||||||
|
#[inline(always)]
|
||||||
|
pub unsafe fn read_and_zero_ptr<T>(dest: *mut T) -> T {
|
||||||
|
// Copy the data out from `dest`:
|
||||||
|
let tmp = read_ptr(dest);
|
||||||
|
|
||||||
|
// Now zero out `dest`:
|
||||||
|
zero_memory(dest, 1);
|
||||||
|
|
||||||
|
tmp
|
||||||
|
}
|
||||||
|
|
||||||
/// Transform a region pointer - &T - to an unsafe pointer - *T.
|
/// Transform a region pointer - &T - to an unsafe pointer - *T.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
|
pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
|
||||||
|
|||||||
@@ -1256,16 +1256,15 @@ impl<T> OwnedVector<T> for ~[T] {
|
|||||||
/// ~~~
|
/// ~~~
|
||||||
#[inline]
|
#[inline]
|
||||||
fn push_all_move(&mut self, mut rhs: ~[T]) {
|
fn push_all_move(&mut self, mut rhs: ~[T]) {
|
||||||
let new_len = self.len() + rhs.len();
|
let self_len = self.len();
|
||||||
|
let rhs_len = rhs.len();
|
||||||
|
let new_len = self_len + rhs_len;
|
||||||
self.reserve(new_len);
|
self.reserve(new_len);
|
||||||
unsafe {
|
unsafe { // Note: infallible.
|
||||||
do rhs.as_mut_buf |p, len| {
|
let self_p = vec::raw::to_mut_ptr(*self);
|
||||||
for uint::range(0, len) |i| {
|
let rhs_p = vec::raw::to_ptr(rhs);
|
||||||
let x = ptr::replace_ptr(ptr::mut_offset(p, i),
|
ptr::copy_memory(ptr::mut_offset(self_p, self_len), rhs_p, rhs_len);
|
||||||
intrinsics::uninit());
|
raw::set_len(self, new_len);
|
||||||
self.push(x);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
raw::set_len(&mut rhs, 0);
|
raw::set_len(&mut rhs, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1277,9 +1276,8 @@ impl<T> OwnedVector<T> for ~[T] {
|
|||||||
ln => {
|
ln => {
|
||||||
let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]);
|
let valptr = ptr::to_mut_unsafe_ptr(&mut self[ln - 1u]);
|
||||||
unsafe {
|
unsafe {
|
||||||
let val = ptr::replace_ptr(valptr, intrinsics::init());
|
raw::set_len(v, ln - 1u);
|
||||||
raw::set_len(self, ln - 1u);
|
ptr::read_ptr(valptr)
|
||||||
Some(val)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1410,7 +1408,7 @@ impl<T> OwnedVector<T> for ~[T] {
|
|||||||
unsafe {
|
unsafe {
|
||||||
// This loop is optimized out for non-drop types.
|
// This loop is optimized out for non-drop types.
|
||||||
for uint::range(newlen, oldlen) |i| {
|
for uint::range(newlen, oldlen) |i| {
|
||||||
ptr::replace_ptr(ptr::mut_offset(p, i), intrinsics::uninit());
|
ptr::read_and_zero_ptr(ptr::mut_offset(p, i))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1555,37 +1553,93 @@ pub trait OwnedEqVector<T:Eq> {
|
|||||||
|
|
||||||
impl<T:Eq> OwnedEqVector<T> for ~[T] {
|
impl<T:Eq> OwnedEqVector<T> for ~[T] {
|
||||||
/**
|
/**
|
||||||
* Remove consecutive repeated elements from a vector; if the vector is
|
* Remove consecutive repeated elements from a vector; if the vector is
|
||||||
* sorted, this removes all duplicates.
|
* sorted, this removes all duplicates.
|
||||||
*/
|
*/
|
||||||
pub fn dedup(&mut self) {
|
pub fn dedup<T:Eq>(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
if self.len() == 0 { return; }
|
// Although we have a mutable reference to `self`, we cannot make
|
||||||
let mut last_written = 0;
|
// *arbitrary* changes. There exists the possibility that this
|
||||||
let mut next_to_read = 1;
|
// vector is contained with an `@mut` box and hence is still
|
||||||
do self.as_mut_buf |p, ln| {
|
// readable by the outside world during the `Eq` comparisons.
|
||||||
// last_written < next_to_read <= ln
|
// Moreover, those comparisons could fail, so we must ensure
|
||||||
while next_to_read < ln {
|
// that the vector is in a valid state at all time.
|
||||||
// last_written < next_to_read < ln
|
//
|
||||||
if *ptr::mut_offset(p, next_to_read) ==
|
// The way that we handle this is by using swaps; we iterate
|
||||||
*ptr::mut_offset(p, last_written) {
|
// over all the elements, swapping as we go so that at the end
|
||||||
ptr::replace_ptr(ptr::mut_offset(p, next_to_read),
|
// the elements we wish to keep are in the front, and those we
|
||||||
intrinsics::uninit());
|
// wish to reject are at the back. We can then truncate the
|
||||||
} else {
|
// vector. This operation is still O(n).
|
||||||
last_written += 1;
|
//
|
||||||
// last_written <= next_to_read < ln
|
// Example: We start in this state, where `r` represents "next
|
||||||
if next_to_read != last_written {
|
// read" and `w` represents "next_write`.
|
||||||
ptr::swap_ptr(ptr::mut_offset(p, last_written),
|
//
|
||||||
ptr::mut_offset(p, next_to_read));
|
// r
|
||||||
}
|
// +---+---+---+---+---+---+
|
||||||
|
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// w
|
||||||
|
//
|
||||||
|
// Comparing self[r] against self[w-1], tis is not a duplicate, so
|
||||||
|
// we swap self[r] and self[w] (no effect as r==w) and then increment both
|
||||||
|
// r and w, leaving us with:
|
||||||
|
//
|
||||||
|
// r
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// w
|
||||||
|
//
|
||||||
|
// Comparing self[r] against self[w-1], this value is a duplicate,
|
||||||
|
// so we increment `r` but leave everything else unchanged:
|
||||||
|
//
|
||||||
|
// r
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// | 0 | 1 | 1 | 2 | 3 | 3 |
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// w
|
||||||
|
//
|
||||||
|
// Comparing self[r] against self[w-1], this is not a duplicate,
|
||||||
|
// so swap self[r] and self[w] and advance r and w:
|
||||||
|
//
|
||||||
|
// r
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// | 0 | 1 | 2 | 1 | 3 | 3 |
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// w
|
||||||
|
//
|
||||||
|
// Not a duplicate, repeat:
|
||||||
|
//
|
||||||
|
// r
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// | 0 | 1 | 2 | 3 | 1 | 3 |
|
||||||
|
// +---+---+---+---+---+---+
|
||||||
|
// w
|
||||||
|
//
|
||||||
|
// Duplicate, advance r. End of vec. Truncate to w.
|
||||||
|
|
||||||
|
let ln = self.len();
|
||||||
|
if ln < 1 { return; }
|
||||||
|
|
||||||
|
// Avoid bounds checks by using unsafe pointers.
|
||||||
|
let p = vec::raw::to_mut_ptr(*self);
|
||||||
|
let mut r = 1;
|
||||||
|
let mut w = 1;
|
||||||
|
|
||||||
|
while r < ln {
|
||||||
|
let p_r = ptr::mut_offset(p, r);
|
||||||
|
let p_wm1 = ptr::mut_offset(p, w - 1);
|
||||||
|
if *p_r != *p_wm1 {
|
||||||
|
if r != w {
|
||||||
|
let p_w = ptr::mut_offset(p_wm1, 1);
|
||||||
|
util::swap(&mut *p_r, &mut *p_w);
|
||||||
}
|
}
|
||||||
// last_written <= next_to_read < ln
|
w += 1;
|
||||||
next_to_read += 1;
|
|
||||||
// last_written < next_to_read <= ln
|
|
||||||
}
|
}
|
||||||
|
r += 1;
|
||||||
}
|
}
|
||||||
// last_written < next_to_read == ln
|
|
||||||
raw::set_len(self, last_written + 1);
|
self.truncate(w);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user