Skip to content

Add vec::dedup for in-place consecutive duplicate element removal. #3440

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 12, 2012
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions src/libcore/vec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ export grow;
export grow_fn;
export grow_set;
export truncate;
export dedup;
export map;
export mapi;
export map2;
Expand Down Expand Up @@ -625,6 +626,41 @@ fn truncate<T>(&v: ~[const T], newlen: uint) {
}
}

/**
* Remove consecutive repeated elements from a vector; if the vector is
* sorted, this removes all duplicates.
*/
fn dedup<T: Eq>(&v: ~[const T]) unsafe {
if v.len() < 1 { return; }
let mut last_written = 0, next_to_read = 1;
do as_const_buf(v) |p, ln| {
// We have a mutable reference to v, so we can make arbitrary changes.
// (cf. push and pop)
let p = p as *mut T;
// last_written < next_to_read <= ln
while next_to_read < ln {
// last_written < next_to_read < ln
if *ptr::mut_offset(p, next_to_read) ==
*ptr::mut_offset(p, last_written) {
let _dropped <- *ptr::mut_offset(p, next_to_read);
} else {
last_written += 1;
// last_written <= next_to_read < ln
if next_to_read != last_written {
*ptr::mut_offset(p, last_written) <-
*ptr::mut_offset(p, next_to_read);
}
}
// last_written <= next_to_read < ln
next_to_read += 1;
// last_written < next_to_read <= ln
}
}
// last_written < next_to_read == ln
unsafe::set_len(v, last_written + 1);
}


// Appending
#[inline(always)]
pure fn append<T: Copy>(+lhs: ~[T], rhs: &[const T]) -> ~[T] {
Expand Down Expand Up @@ -2218,6 +2254,51 @@ mod tests {
// If the unsafe block didn't drop things properly, we blow up here.
}

#[test]
fn test_dedup() {
fn case(-a: ~[uint], -b: ~[uint]) {
let mut v = a;
dedup(v);
assert(v == b);
}
case(~[], ~[]);
case(~[1], ~[1]);
case(~[1,1], ~[1]);
case(~[1,2,3], ~[1,2,3]);
case(~[1,1,2,3], ~[1,2,3]);
case(~[1,2,2,3], ~[1,2,3]);
case(~[1,2,3,3], ~[1,2,3]);
case(~[1,1,2,2,2,3,3], ~[1,2,3]);
}

#[test]
fn test_dedup_unique() {
let mut v0 = ~[~1, ~1, ~2, ~3];
dedup(v0);
let mut v1 = ~[~1, ~2, ~2, ~3];
dedup(v1);
let mut v2 = ~[~1, ~2, ~3, ~3];
dedup(v2);
/*
* If the ~pointers were leaked or otherwise misused, valgrind and/or
* rustrt should raise errors.
*/
}

#[test]
fn test_dedup_shared() {
let mut v0 = ~[@1, @1, @2, @3];
dedup(v0);
let mut v1 = ~[@1, @2, @2, @3];
dedup(v1);
let mut v2 = ~[@1, @2, @3, @3];
dedup(v2);
/*
* If the @pointers were leaked or otherwise misused, valgrind and/or
* rustrt should raise errors.
*/
}

#[test]
fn test_map() {
// Test on-stack map.
Expand Down