| /*! |
| |
| A doubly-linked list. Supports O(1) head, tail, count, push, pop, etc. |
| |
| # Safety note |
| |
| Do not use ==, !=, <, etc on doubly-linked lists -- it may not terminate. |
| |
| */ |
| |
| // NB: transitionary, de-mode-ing. |
| #[forbid(deprecated_mode)]; |
| #[forbid(deprecated_pattern)]; |
| |
| type DListLink<T> = Option<DListNode<T>>; |
| |
| enum DListNode<T> = @{ |
| data: T, |
| mut linked: bool, // for assertions |
| mut prev: DListLink<T>, |
| mut next: DListLink<T> |
| }; |
| |
| pub enum DList<T> { |
| DList_(@{ |
| mut size: uint, |
| mut hd: DListLink<T>, |
| mut tl: DListLink<T> |
| }) |
| } |
| |
| priv impl<T> DListNode<T> { |
| pure fn assert_links() { |
| match self.next { |
| Some(neighbour) => match neighbour.prev { |
| Some(me) => if !box::ptr_eq(*self, *me) { |
| fail ~"Asymmetric next-link in dlist node." |
| }, |
| None => fail ~"One-way next-link in dlist node." |
| }, |
| None => () |
| } |
| match self.prev { |
| Some(neighbour) => match neighbour.next { |
| Some(me) => if !box::ptr_eq(*me, *self) { |
| fail ~"Asymmetric prev-link in dlist node." |
| }, |
| None => fail ~"One-way prev-link in dlist node." |
| }, |
| None => () |
| } |
| } |
| } |
| |
| impl<T> DListNode<T> { |
| /// Get the next node in the list, if there is one. |
| pure fn next_link() -> Option<DListNode<T>> { |
| self.assert_links(); |
| self.next |
| } |
| /// Get the next node in the list, failing if there isn't one. |
| pure fn next_node() -> DListNode<T> { |
| match self.next_link() { |
| Some(nobe) => nobe, |
| None => fail ~"This dlist node has no next neighbour." |
| } |
| } |
| /// Get the previous node in the list, if there is one. |
| pure fn prev_link() -> Option<DListNode<T>> { |
| self.assert_links(); |
| self.prev |
| } |
| /// Get the previous node in the list, failing if there isn't one. |
| pure fn prev_node() -> DListNode<T> { |
| match self.prev_link() { |
| Some(nobe) => nobe, |
| None => fail ~"This dlist node has no previous neighbour." |
| } |
| } |
| } |
| |
| /// Creates a new dlist node with the given data. |
| pure fn new_dlist_node<T>(data: T) -> DListNode<T> { |
| DListNode(@{data: move data, mut linked: false, |
| mut prev: None, mut next: None}) |
| } |
| |
| /// Creates a new, empty dlist. |
| pure fn DList<T>() -> DList<T> { |
| DList_(@{mut size: 0, mut hd: None, mut tl: None}) |
| } |
| |
| /// Creates a new dlist with a single element |
| pub pure fn from_elem<T>(data: T) -> DList<T> { |
| let list = DList(); |
| unsafe { list.push(move data); } |
| list |
| } |
| |
| pub fn from_vec<T: Copy>(vec: &[T]) -> DList<T> { |
| do vec::foldl(DList(), vec) |list,data| { |
| list.push(*data); // Iterating left-to-right -- add newly to the tail. |
| list |
| } |
| } |
| |
| /// Produce a list from a list of lists, leaving no elements behind in the |
| /// input. O(number of sub-lists). |
| fn concat<T>(lists: DList<DList<T>>) -> DList<T> { |
| let result = DList(); |
| while !lists.is_empty() { |
| result.append(lists.pop().get()); |
| } |
| result |
| } |
| |
| priv impl<T> DList<T> { |
| pure fn new_link(data: T) -> DListLink<T> { |
| Some(DListNode(@{data: move data, mut linked: true, |
| mut prev: None, mut next: None})) |
| } |
| pure fn assert_mine(nobe: DListNode<T>) { |
| // These asserts could be stronger if we had node-root back-pointers, |
| // but those wouldn't allow for O(1) append. |
| if self.size == 0 { |
| fail ~"This dlist is empty; that node can't be on it." |
| } |
| if !nobe.linked { fail ~"That node isn't linked to any dlist." } |
| if !((nobe.prev.is_some() |
| || box::ptr_eq(*self.hd.expect(~"headless dlist?"), *nobe)) && |
| (nobe.next.is_some() |
| || box::ptr_eq(*self.tl.expect(~"tailless dlist?"), *nobe))) { |
| fail ~"That node isn't on this dlist." |
| } |
| } |
| fn make_mine(nobe: DListNode<T>) { |
| if nobe.prev.is_some() || nobe.next.is_some() || nobe.linked { |
| fail ~"Cannot insert node that's already on a dlist!" |
| } |
| nobe.linked = true; |
| } |
| // Link two nodes together. If either of them are 'none', also sets |
| // the head and/or tail pointers appropriately. |
| #[inline(always)] |
| fn link(before: DListLink<T>, after: DListLink<T>) { |
| match before { |
| Some(neighbour) => neighbour.next = after, |
| None => self.hd = after |
| } |
| match after { |
| Some(neighbour) => neighbour.prev = before, |
| None => self.tl = before |
| } |
| } |
| // Remove a node from the list. |
| fn unlink(nobe: DListNode<T>) { |
| self.assert_mine(nobe); |
| assert self.size > 0; |
| self.link(nobe.prev, nobe.next); |
| nobe.prev = None; // Release extraneous references. |
| nobe.next = None; |
| nobe.linked = false; |
| self.size -= 1; |
| } |
| |
| fn add_head(nobe: DListLink<T>) { |
| self.link(nobe, self.hd); // Might set tail too. |
| self.hd = nobe; |
| self.size += 1; |
| } |
| fn add_tail(nobe: DListLink<T>) { |
| self.link(self.tl, nobe); // Might set head too. |
| self.tl = nobe; |
| self.size += 1; |
| } |
| fn insert_left(nobe: DListLink<T>, neighbour: DListNode<T>) { |
| self.assert_mine(neighbour); |
| assert self.size > 0; |
| self.link(neighbour.prev, nobe); |
| self.link(nobe, Some(neighbour)); |
| self.size += 1; |
| } |
| fn insert_right(neighbour: DListNode<T>, nobe: DListLink<T>) { |
| self.assert_mine(neighbour); |
| assert self.size > 0; |
| self.link(nobe, neighbour.next); |
| self.link(Some(neighbour), nobe); |
| self.size += 1; |
| } |
| } |
| |
| impl<T> DList<T> { |
| /// Get the size of the list. O(1). |
| pure fn len() -> uint { self.size } |
| /// Returns true if the list is empty. O(1). |
| pure fn is_empty() -> bool { self.len() == 0 } |
| /// Returns true if the list is not empty. O(1). |
| pure fn is_not_empty() -> bool { self.len() != 0 } |
| |
| /// Add data to the head of the list. O(1). |
| fn push_head(data: T) { |
| self.add_head(self.new_link(move data)); |
| } |
| /** |
| * Add data to the head of the list, and get the new containing |
| * node. O(1). |
| */ |
| fn push_head_n(data: T) -> DListNode<T> { |
| let mut nobe = self.new_link(move data); |
| self.add_head(nobe); |
| option::get(&nobe) |
| } |
| /// Add data to the tail of the list. O(1). |
| fn push(data: T) { |
| self.add_tail(self.new_link(move data)); |
| } |
| /** |
| * Add data to the tail of the list, and get the new containing |
| * node. O(1). |
| */ |
| fn push_n(data: T) -> DListNode<T> { |
| let mut nobe = self.new_link(move data); |
| self.add_tail(nobe); |
| option::get(&nobe) |
| } |
| /** |
| * Insert data into the middle of the list, left of the given node. |
| * O(1). |
| */ |
| fn insert_before(data: T, neighbour: DListNode<T>) { |
| self.insert_left(self.new_link(move data), neighbour); |
| } |
| /** |
| * Insert an existing node in the middle of the list, left of the |
| * given node. O(1). |
| */ |
| fn insert_n_before(nobe: DListNode<T>, neighbour: DListNode<T>) { |
| self.make_mine(nobe); |
| self.insert_left(Some(nobe), neighbour); |
| } |
| /** |
| * Insert data in the middle of the list, left of the given node, |
| * and get its containing node. O(1). |
| */ |
| fn insert_before_n(data: T, neighbour: DListNode<T>) -> DListNode<T> { |
| let mut nobe = self.new_link(move data); |
| self.insert_left(nobe, neighbour); |
| option::get(&nobe) |
| } |
| /** |
| * Insert data into the middle of the list, right of the given node. |
| * O(1). |
| */ |
| fn insert_after(data: T, neighbour: DListNode<T>) { |
| self.insert_right(neighbour, self.new_link(move data)); |
| } |
| /** |
| * Insert an existing node in the middle of the list, right of the |
| * given node. O(1). |
| */ |
| fn insert_n_after(nobe: DListNode<T>, neighbour: DListNode<T>) { |
| self.make_mine(nobe); |
| self.insert_right(neighbour, Some(nobe)); |
| } |
| /** |
| * Insert data in the middle of the list, right of the given node, |
| * and get its containing node. O(1). |
| */ |
| fn insert_after_n(data: T, neighbour: DListNode<T>) -> DListNode<T> { |
| let mut nobe = self.new_link(move data); |
| self.insert_right(neighbour, nobe); |
| option::get(&nobe) |
| } |
| |
| /// Remove a node from the head of the list. O(1). |
| fn pop_n() -> Option<DListNode<T>> { |
| let hd = self.peek_n(); |
| hd.map(|nobe| self.unlink(*nobe)); |
| hd |
| } |
| /// Remove a node from the tail of the list. O(1). |
| fn pop_tail_n() -> Option<DListNode<T>> { |
| let tl = self.peek_tail_n(); |
| tl.map(|nobe| self.unlink(*nobe)); |
| tl |
| } |
| /// Get the node at the list's head. O(1). |
| pure fn peek_n() -> Option<DListNode<T>> { self.hd } |
| /// Get the node at the list's tail. O(1). |
| pure fn peek_tail_n() -> Option<DListNode<T>> { self.tl } |
| |
| /// Get the node at the list's head, failing if empty. O(1). |
| pure fn head_n() -> DListNode<T> { |
| match self.hd { |
| Some(nobe) => nobe, |
| None => fail ~"Attempted to get the head of an empty dlist." |
| } |
| } |
| /// Get the node at the list's tail, failing if empty. O(1). |
| pure fn tail_n() -> DListNode<T> { |
| match self.tl { |
| Some(nobe) => nobe, |
| None => fail ~"Attempted to get the tail of an empty dlist." |
| } |
| } |
| |
| /// Remove a node from anywhere in the list. O(1). |
| fn remove(nobe: DListNode<T>) { self.unlink(nobe); } |
| |
| /** |
| * Empty another list onto the end of this list, joining this list's tail |
| * to the other list's head. O(1). |
| */ |
| fn append(them: DList<T>) { |
| if box::ptr_eq(*self, *them) { |
| fail ~"Cannot append a dlist to itself!" |
| } |
| if them.len() > 0 { |
| self.link(self.tl, them.hd); |
| self.tl = them.tl; |
| self.size += them.size; |
| them.size = 0; |
| them.hd = None; |
| them.tl = None; |
| } |
| } |
| /** |
| * Empty another list onto the start of this list, joining the other |
| * list's tail to this list's head. O(1). |
| */ |
| fn prepend(them: DList<T>) { |
| if box::ptr_eq(*self, *them) { |
| fail ~"Cannot prepend a dlist to itself!" |
| } |
| if them.len() > 0 { |
| self.link(them.tl, self.hd); |
| self.hd = them.hd; |
| self.size += them.size; |
| them.size = 0; |
| them.hd = None; |
| them.tl = None; |
| } |
| } |
| |
| /// Reverse the list's elements in place. O(n). |
| fn reverse() { |
| do option::while_some(self.hd) |nobe| { |
| let next_nobe = nobe.next; |
| self.remove(nobe); |
| self.make_mine(nobe); |
| self.add_head(Some(nobe)); |
| next_nobe |
| } |
| } |
| |
| /** |
| * Remove everything from the list. This is important because the cyclic |
| * links won't otherwise be automatically refcounted-collected. O(n). |
| */ |
| fn clear() { |
| // Cute as it would be to simply detach the list and proclaim "O(1)!", |
| // the GC would still be a hidden O(n). Better to be honest about it. |
| while !self.is_empty() { |
| let _ = self.pop_n(); |
| } |
| } |
| |
| /// Iterate over nodes. |
| pure fn each_node(f: fn(DListNode<T>) -> bool) { |
| let mut link = self.peek_n(); |
| while link.is_some() { |
| let nobe = link.get(); |
| if !f(nobe) { break; } |
| link = nobe.next_link(); |
| } |
| } |
| |
| /// Check data structure integrity. O(n). |
| fn assert_consistent() { |
| if option::is_none(&self.hd) || option::is_none(&self.tl) { |
| assert option::is_none(&self.hd) && option::is_none(&self.tl); |
| } |
| // iterate forwards |
| let mut count = 0; |
| let mut link = self.peek_n(); |
| let mut rabbit = link; |
| while option::is_some(&link) { |
| let nobe = option::get(&link); |
| assert nobe.linked; |
| // check cycle |
| if option::is_some(&rabbit) { |
| rabbit = option::get(&rabbit).next; |
| } |
| if option::is_some(&rabbit) { |
| rabbit = option::get(&rabbit).next; |
| } |
| if option::is_some(&rabbit) { |
| assert !box::ptr_eq(*option::get(&rabbit), *nobe); |
| } |
| // advance |
| link = nobe.next_link(); |
| count += 1; |
| } |
| assert count == self.len(); |
| // iterate backwards - some of this is probably redundant. |
| link = self.peek_tail_n(); |
| rabbit = link; |
| while option::is_some(&link) { |
| let nobe = option::get(&link); |
| assert nobe.linked; |
| // check cycle |
| if option::is_some(&rabbit) { |
| rabbit = option::get(&rabbit).prev; |
| } |
| if option::is_some(&rabbit) { |
| rabbit = option::get(&rabbit).prev; |
| } |
| if option::is_some(&rabbit) { |
| assert !box::ptr_eq(*option::get(&rabbit), *nobe); |
| } |
| // advance |
| link = nobe.prev_link(); |
| count -= 1; |
| } |
| assert count == 0; |
| } |
| } |
| |
| impl<T: Copy> DList<T> { |
| /// Remove data from the head of the list. O(1). |
| fn pop() -> Option<T> { self.pop_n().map (|nobe| nobe.data) } |
| /// Remove data from the tail of the list. O(1). |
| fn pop_tail() -> Option<T> { self.pop_tail_n().map (|nobe| nobe.data) } |
| /// Get data at the list's head. O(1). |
| pure fn peek() -> Option<T> { self.peek_n().map (|nobe| nobe.data) } |
| /// Get data at the list's tail. O(1). |
| pure fn peek_tail() -> Option<T> { |
| self.peek_tail_n().map (|nobe| nobe.data) |
| } |
| /// Get data at the list's head, failing if empty. O(1). |
| pure fn head() -> T { self.head_n().data } |
| /// Get data at the list's tail, failing if empty. O(1). |
| pure fn tail() -> T { self.tail_n().data } |
| /// Get the elements of the list as a vector. O(n). |
| pure fn to_vec() -> ~[T] { |
| let mut v = vec::with_capacity(self.size); |
| unsafe { |
| // Take this out of the unchecked when iter's functions are pure |
| for self.eachi |index,data| { |
| v[index] = *data; |
| } |
| } |
| move v |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| #[legacy_exports]; |
| #[test] |
| fn test_dlist_concat() { |
| let a = from_vec(~[1,2]); |
| let b = from_vec(~[3,4]); |
| let c = from_vec(~[5,6]); |
| let d = from_vec(~[7,8]); |
| let ab = from_vec(~[a,b]); |
| let cd = from_vec(~[c,d]); |
| let abcd = concat(concat(from_vec(~[ab,cd]))); |
| abcd.assert_consistent(); assert abcd.len() == 8; |
| abcd.assert_consistent(); assert abcd.pop().get() == 1; |
| abcd.assert_consistent(); assert abcd.pop().get() == 2; |
| abcd.assert_consistent(); assert abcd.pop().get() == 3; |
| abcd.assert_consistent(); assert abcd.pop().get() == 4; |
| abcd.assert_consistent(); assert abcd.pop().get() == 5; |
| abcd.assert_consistent(); assert abcd.pop().get() == 6; |
| abcd.assert_consistent(); assert abcd.pop().get() == 7; |
| abcd.assert_consistent(); assert abcd.pop().get() == 8; |
| abcd.assert_consistent(); assert abcd.is_empty(); |
| } |
| #[test] |
| fn test_dlist_append() { |
| let a = from_vec(~[1,2,3]); |
| let b = from_vec(~[4,5,6]); |
| a.append(b); |
| assert a.len() == 6; |
| assert b.len() == 0; |
| b.assert_consistent(); |
| a.assert_consistent(); assert a.pop().get() == 1; |
| a.assert_consistent(); assert a.pop().get() == 2; |
| a.assert_consistent(); assert a.pop().get() == 3; |
| a.assert_consistent(); assert a.pop().get() == 4; |
| a.assert_consistent(); assert a.pop().get() == 5; |
| a.assert_consistent(); assert a.pop().get() == 6; |
| a.assert_consistent(); assert a.is_empty(); |
| } |
| #[test] |
| fn test_dlist_append_empty() { |
| let a = from_vec(~[1,2,3]); |
| let b = DList::<int>(); |
| a.append(b); |
| assert a.len() == 3; |
| assert b.len() == 0; |
| b.assert_consistent(); |
| a.assert_consistent(); assert a.pop().get() == 1; |
| a.assert_consistent(); assert a.pop().get() == 2; |
| a.assert_consistent(); assert a.pop().get() == 3; |
| a.assert_consistent(); assert a.is_empty(); |
| } |
| #[test] |
| fn test_dlist_append_to_empty() { |
| let a = DList::<int>(); |
| let b = from_vec(~[4,5,6]); |
| a.append(b); |
| assert a.len() == 3; |
| assert b.len() == 0; |
| b.assert_consistent(); |
| a.assert_consistent(); assert a.pop().get() == 4; |
| a.assert_consistent(); assert a.pop().get() == 5; |
| a.assert_consistent(); assert a.pop().get() == 6; |
| a.assert_consistent(); assert a.is_empty(); |
| } |
| #[test] |
| fn test_dlist_append_two_empty() { |
| let a = DList::<int>(); |
| let b = DList::<int>(); |
| a.append(b); |
| assert a.len() == 0; |
| assert b.len() == 0; |
| b.assert_consistent(); |
| a.assert_consistent(); |
| } |
| #[test] |
| #[ignore(cfg(windows))] |
| #[should_fail] |
| fn test_dlist_append_self() { |
| let a = DList::<int>(); |
| a.append(a); |
| } |
| #[test] |
| #[ignore(cfg(windows))] |
| #[should_fail] |
| fn test_dlist_prepend_self() { |
| let a = DList::<int>(); |
| a.prepend(a); |
| } |
| #[test] |
| fn test_dlist_prepend() { |
| let a = from_vec(~[1,2,3]); |
| let b = from_vec(~[4,5,6]); |
| b.prepend(a); |
| assert a.len() == 0; |
| assert b.len() == 6; |
| a.assert_consistent(); |
| b.assert_consistent(); assert b.pop().get() == 1; |
| b.assert_consistent(); assert b.pop().get() == 2; |
| b.assert_consistent(); assert b.pop().get() == 3; |
| b.assert_consistent(); assert b.pop().get() == 4; |
| b.assert_consistent(); assert b.pop().get() == 5; |
| b.assert_consistent(); assert b.pop().get() == 6; |
| b.assert_consistent(); assert b.is_empty(); |
| } |
| #[test] |
| fn test_dlist_reverse() { |
| let a = from_vec(~[5,4,3,2,1]); |
| a.reverse(); |
| assert a.len() == 5; |
| a.assert_consistent(); assert a.pop().get() == 1; |
| a.assert_consistent(); assert a.pop().get() == 2; |
| a.assert_consistent(); assert a.pop().get() == 3; |
| a.assert_consistent(); assert a.pop().get() == 4; |
| a.assert_consistent(); assert a.pop().get() == 5; |
| a.assert_consistent(); assert a.is_empty(); |
| } |
| #[test] |
| fn test_dlist_reverse_empty() { |
| let a = DList::<int>(); |
| a.reverse(); |
| assert a.len() == 0; |
| a.assert_consistent(); |
| } |
| #[test] |
| fn test_dlist_each_node() { |
| let a = from_vec(~[1,2,4,5]); |
| for a.each_node |nobe| { |
| if nobe.data > 3 { |
| a.insert_before(3, nobe); |
| } |
| } |
| assert a.len() == 6; |
| a.assert_consistent(); assert a.pop().get() == 1; |
| a.assert_consistent(); assert a.pop().get() == 2; |
| a.assert_consistent(); assert a.pop().get() == 3; |
| a.assert_consistent(); assert a.pop().get() == 4; |
| a.assert_consistent(); assert a.pop().get() == 3; |
| a.assert_consistent(); assert a.pop().get() == 5; |
| a.assert_consistent(); assert a.is_empty(); |
| } |
| #[test] |
| fn test_dlist_clear() { |
| let a = from_vec(~[5,4,3,2,1]); |
| a.clear(); |
| assert a.len() == 0; |
| a.assert_consistent(); |
| } |
| #[test] |
| fn test_dlist_is_empty() { |
| let empty = DList::<int>(); |
| let full1 = from_vec(~[1,2,3]); |
| assert empty.is_empty(); |
| assert !full1.is_empty(); |
| assert !empty.is_not_empty(); |
| assert full1.is_not_empty(); |
| } |
| #[test] |
| fn test_dlist_head_tail() { |
| let l = from_vec(~[1,2,3]); |
| assert l.head() == 1; |
| assert l.tail() == 3; |
| assert l.len() == 3; |
| } |
| #[test] |
| fn test_dlist_pop() { |
| let l = from_vec(~[1,2,3]); |
| assert l.pop().get() == 1; |
| assert l.tail() == 3; |
| assert l.head() == 2; |
| assert l.pop().get() == 2; |
| assert l.tail() == 3; |
| assert l.head() == 3; |
| assert l.pop().get() == 3; |
| assert l.is_empty(); |
| assert l.pop().is_none(); |
| } |
| #[test] |
| fn test_dlist_pop_tail() { |
| let l = from_vec(~[1,2,3]); |
| assert l.pop_tail().get() == 3; |
| assert l.tail() == 2; |
| assert l.head() == 1; |
| assert l.pop_tail().get() == 2; |
| assert l.tail() == 1; |
| assert l.head() == 1; |
| assert l.pop_tail().get() == 1; |
| assert l.is_empty(); |
| assert l.pop_tail().is_none(); |
| } |
| #[test] |
| fn test_dlist_push() { |
| let l = DList::<int>(); |
| l.push(1); |
| assert l.head() == 1; |
| assert l.tail() == 1; |
| l.push(2); |
| assert l.head() == 1; |
| assert l.tail() == 2; |
| l.push(3); |
| assert l.head() == 1; |
| assert l.tail() == 3; |
| assert l.len() == 3; |
| } |
| #[test] |
| fn test_dlist_push_head() { |
| let l = DList::<int>(); |
| l.push_head(3); |
| assert l.head() == 3; |
| assert l.tail() == 3; |
| l.push_head(2); |
| assert l.head() == 2; |
| assert l.tail() == 3; |
| l.push_head(1); |
| assert l.head() == 1; |
| assert l.tail() == 3; |
| assert l.len() == 3; |
| } |
| #[test] |
| fn test_dlist_foldl() { |
| let l = from_vec(vec::from_fn(101, |x|x)); |
| assert iter::foldl(&l, 0, |accum,elem| *accum+*elem) == 5050; |
| } |
| #[test] |
| fn test_dlist_break_early() { |
| let l = from_vec(~[1,2,3,4,5]); |
| let mut x = 0; |
| for l.each |i| { |
| x += 1; |
| if (*i == 3) { break; } |
| } |
| assert x == 3; |
| } |
| #[test] |
| fn test_dlist_remove_head() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let _two = l.push_n(2); |
| l.assert_consistent(); let _three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(one); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); assert l.head() == 2; |
| l.assert_consistent(); assert l.tail() == 3; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_mid() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let _one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); let _three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(two); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 3; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_tail() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let _one = l.push_n(1); |
| l.assert_consistent(); let _two = l.push_n(2); |
| l.assert_consistent(); let three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(three); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 2; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_one_two() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); let _three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(one); |
| l.assert_consistent(); l.remove(two); |
| // and through and through, the vorpal blade went snicker-snack |
| l.assert_consistent(); assert l.len() == 1; |
| l.assert_consistent(); assert l.head() == 3; |
| l.assert_consistent(); assert l.tail() == 3; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_one_three() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let _two = l.push_n(2); |
| l.assert_consistent(); let three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(one); |
| l.assert_consistent(); l.remove(three); |
| l.assert_consistent(); assert l.len() == 1; |
| l.assert_consistent(); assert l.head() == 2; |
| l.assert_consistent(); assert l.tail() == 2; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_two_three() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let _one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); let three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(two); |
| l.assert_consistent(); l.remove(three); |
| l.assert_consistent(); assert l.len() == 1; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 1; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_remove_all() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); let three = l.push_n(3); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); l.remove(two); |
| l.assert_consistent(); l.remove(three); |
| l.assert_consistent(); l.remove(one); // Twenty-three is number one! |
| l.assert_consistent(); assert l.peek().is_none(); |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_insert_n_before() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let _one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); let three = new_dlist_node(3); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); l.insert_n_before(three, two); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 2; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_insert_n_after() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let _two = l.push_n(2); |
| l.assert_consistent(); let three = new_dlist_node(3); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); l.insert_n_after(three, one); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 2; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_insert_before_head() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let one = l.push_n(1); |
| l.assert_consistent(); let _two = l.push_n(2); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); l.insert_before(3, one); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); assert l.head() == 3; |
| l.assert_consistent(); assert l.tail() == 2; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] |
| fn test_dlist_insert_after_tail() { |
| let l = DList::<int>(); |
| l.assert_consistent(); let _one = l.push_n(1); |
| l.assert_consistent(); let two = l.push_n(2); |
| l.assert_consistent(); assert l.len() == 2; |
| l.assert_consistent(); l.insert_after(3, two); |
| l.assert_consistent(); assert l.len() == 3; |
| l.assert_consistent(); assert l.head() == 1; |
| l.assert_consistent(); assert l.tail() == 3; |
| l.assert_consistent(); assert l.pop().get() == 1; |
| l.assert_consistent(); assert l.pop().get() == 2; |
| l.assert_consistent(); assert l.pop().get() == 3; |
| l.assert_consistent(); assert l.is_empty(); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_asymmetric_link() { |
| let l = DList::<int>(); |
| let _one = l.push_n(1); |
| let two = l.push_n(2); |
| two.prev = None; |
| l.assert_consistent(); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_cyclic_list() { |
| let l = DList::<int>(); |
| let one = l.push_n(1); |
| let _two = l.push_n(2); |
| let three = l.push_n(3); |
| three.next = Some(one); |
| one.prev = Some(three); |
| l.assert_consistent(); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_headless() { |
| DList::<int>().head(); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_insert_already_present_before() { |
| let l = DList::<int>(); |
| let one = l.push_n(1); |
| let two = l.push_n(2); |
| l.insert_n_before(two, one); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_insert_already_present_after() { |
| let l = DList::<int>(); |
| let one = l.push_n(1); |
| let two = l.push_n(2); |
| l.insert_n_after(one, two); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_insert_before_orphan() { |
| let l = DList::<int>(); |
| let one = new_dlist_node(1); |
| let two = new_dlist_node(2); |
| l.insert_n_before(one, two); |
| } |
| #[test] #[should_fail] #[ignore(cfg(windows))] |
| fn test_dlist_insert_after_orphan() { |
| let l = DList::<int>(); |
| let one = new_dlist_node(1); |
| let two = new_dlist_node(2); |
| l.insert_n_after(two, one); |
| } |
| } |