Skip to content

Commit

Permalink
auto merge of #20406 : TimDumol/rust/dlist-append-split-off, r=Gankro
Browse files Browse the repository at this point in the history
Implements the `append()` and `split_off()` methods proposed by the collections reform part 2 RFC.

RFC: rust-lang/rfcs#509
Tracking issue: #19986
  • Loading branch information
bors committed Jan 11, 2015
2 parents 2e4cef4 + d0bc031 commit 32ddbb8
Showing 1 changed file with 161 additions and 41 deletions.
202 changes: 161 additions & 41 deletions src/libcollections/dlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,9 +221,12 @@ impl<T> DList<T> {
DList{list_head: None, list_tail: Rawlink::none(), length: 0}
}

/// Adds all elements from `other` to the end of the list.
/// Moves all elements from `other` to the end of the list.
///
/// This operation should compute in O(1) time.
/// This reuses all the nodes from `other` and moves them into `self`. After
/// this operation, `other` becomes empty.
///
/// This operation should compute in O(1) time and O(1) memory.
///
/// # Examples
///
Expand All @@ -237,16 +240,20 @@ impl<T> DList<T> {
/// b.push_back(3i);
/// b.push_back(4);
///
/// a.append(b);
/// a.append(&mut b);
///
/// for e in a.iter() {
/// println!("{}", e); // prints 1, then 2, then 3, then 4
/// }
/// println!("{}", b.len()); // prints 0
/// ```
#[unstable = "append should be by-mutable-reference"]
pub fn append(&mut self, mut other: DList<T>) {
pub fn append(&mut self, other: &mut DList<T>) {
match self.list_tail.resolve() {
None => *self = other,
None => {
self.length = other.length;
self.list_head = other.list_head.take();
self.list_tail = other.list_tail.take();
},
Some(tail) => {
// Carefully empty `other`.
let o_tail = other.list_tail.take();
Expand All @@ -261,6 +268,7 @@ impl<T> DList<T> {
}
}
}
other.length = 0;
}

/// Provides a forward iterator.
Expand Down Expand Up @@ -404,6 +412,51 @@ impl<T> DList<T> {
pub fn pop_back(&mut self) -> Option<T> {
self.pop_back_node().map(|box Node{value, ..}| value)
}

/// Splits the list into two at the given index. Returns everything after the given index,
/// including the index.
///
/// This operation should compute in O(n) time.
#[stable]
pub fn split_off(&mut self, at: uint) -> DList<T> {
let len = self.len();
assert!(at < len, "Cannot split off at a nonexistent index");
if at == 0 {
return mem::replace(self, DList::new());
}

// Below, we iterate towards the `i-1`th node, either from the start or the end,
// depending on which would be faster.
let mut split_node = if at - 1 <= len - 1 - (at - 1) {
let mut iter = self.iter_mut();
// instead of skipping using .skip() (which creates a new struct),
// we skip manually so we can access the head field without
// depending on implementation details of Skip
for _ in range(0, at - 1) {
iter.next();
}
iter.head
} else {
// better off starting from the end
let mut iter = self.iter_mut();
for _ in range(0, len - 1 - (at - 1)) {
iter.next_back();
}
iter.tail
};

let mut splitted_list = DList {
list_head: None,
list_tail: self.list_tail,
length: len - at
};

mem::swap(&mut split_node.resolve().unwrap().next, &mut splitted_list.list_head);
self.list_tail = split_node;
self.length = at;

splitted_list
}
}

#[unsafe_destructor]
Expand Down Expand Up @@ -777,6 +830,108 @@ mod tests {
v.iter().map(|x| (*x).clone()).collect()
}

#[test]
fn test_append() {
// Empty to empty
{
let mut m: DList<int> = DList::new();
let mut n = DList::new();
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 0);
assert_eq!(n.len(), 0);
}
// Non-empty to empty
{
let mut m = DList::new();
let mut n = DList::new();
n.push_back(2i);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
assert_eq!(n.len(), 0);
check_links(&m);
}
// Empty to non-empty
{
let mut m = DList::new();
let mut n = DList::new();
m.push_back(2i);
m.append(&mut n);
check_links(&m);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
check_links(&m);
}

// Non-empty to non-empty
let v = vec![1i,2,3,4,5];
let u = vec![9i,8,1,2,3,4,5];
let mut m = list_from(v.as_slice());
let mut n = list_from(u.as_slice());
m.append(&mut n);
check_links(&m);
let mut sum = v;
sum.push_all(u.as_slice());
assert_eq!(sum.len(), m.len());
for elt in sum.into_iter() {
assert_eq!(m.pop_front(), Some(elt))
}
assert_eq!(n.len(), 0);
// let's make sure it's working properly, since we
// did some direct changes to private members
n.push_back(3);
assert_eq!(n.len(), 1);
assert_eq!(n.pop_front(), Some(3));
check_links(&n);
}

#[test]
fn test_split_off() {
// singleton
{
let mut m = DList::new();
m.push_back(1i);

let p = m.split_off(0);
assert_eq!(m.len(), 0);
assert_eq!(p.len(), 1);
assert_eq!(p.back(), Some(&1));
assert_eq!(p.front(), Some(&1));
}

// not singleton, forwards
{
let u = vec![1i,2,3,4,5];
let mut m = list_from(u.as_slice());
let mut n = m.split_off(2);
assert_eq!(m.len(), 2);
assert_eq!(n.len(), 3);
for elt in range(1i, 3) {
assert_eq!(m.pop_front(), Some(elt));
}
for elt in range(3i, 6) {
assert_eq!(n.pop_front(), Some(elt));
}
}
// not singleton, backwards
{
let u = vec![1i,2,3,4,5];
let mut m = list_from(u.as_slice());
let mut n = m.split_off(4);
assert_eq!(m.len(), 4);
assert_eq!(n.len(), 1);
for elt in range(1i, 5) {
assert_eq!(m.pop_front(), Some(elt));
}
for elt in range(5i, 6) {
assert_eq!(n.pop_front(), Some(elt));
}
}

}

#[test]
fn test_iterator() {
let m = generate_test();
Expand Down Expand Up @@ -1065,41 +1220,6 @@ mod tests {
assert_eq!(i, v.len());
}

#[allow(deprecated)]
#[test]
fn test_append() {
{
let mut m = DList::new();
let mut n = DList::new();
n.push_back(2i);
m.append(n);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
check_links(&m);
}
{
let mut m = DList::new();
let n = DList::new();
m.push_back(2i);
m.append(n);
assert_eq!(m.len(), 1);
assert_eq!(m.pop_back(), Some(2));
check_links(&m);
}

let v = vec![1i,2,3,4,5];
let u = vec![9i,8,1,2,3,4,5];
let mut m = list_from(v.as_slice());
m.append(list_from(u.as_slice()));
check_links(&m);
let mut sum = v;
sum.push_all(u.as_slice());
assert_eq!(sum.len(), m.len());
for elt in sum.into_iter() {
assert_eq!(m.pop_front(), Some(elt))
}
}

#[bench]
fn bench_collect_into(b: &mut test::Bencher) {
let v = &[0i; 64];
Expand Down

0 comments on commit 32ddbb8

Please sign in to comment.