diff --git a/src/libarena/lib.rs b/src/libarena/lib.rs index f2c98b8e5fc38..92ce7e1ff8210 100644 --- a/src/libarena/lib.rs +++ b/src/libarena/lib.rs @@ -28,7 +28,7 @@ extern crate collections; -use collections::list::{List, Cons, Nil}; +use collections::list::List; use std::cast::{transmute, transmute_mut, transmute_mut_region}; use std::cast; @@ -90,7 +90,7 @@ pub struct Arena { // access the head. priv head: Chunk, priv pod_head: Chunk, - priv chunks: RefCell<@List>, + priv chunks: List, priv no_freeze: marker::NoFreeze, } @@ -103,7 +103,7 @@ impl Arena { Arena { head: chunk(initial_size, false), pod_head: chunk(initial_size, true), - chunks: RefCell::new(@Nil), + chunks: List::new(), no_freeze: marker::NoFreeze, } } @@ -122,7 +122,7 @@ impl Drop for Arena { fn drop(&mut self) { unsafe { destroy_chunk(&self.head); - for chunk in self.chunks.get().iter() { + for chunk in self.chunks.iter() { if !chunk.is_pod.get() { destroy_chunk(chunk); } @@ -184,7 +184,7 @@ impl Arena { fn alloc_pod_grow(&mut self, n_bytes: uint, align: uint) -> *u8 { // Allocate a new chunk. let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size()); - self.chunks.set(@Cons(self.pod_head.clone(), self.chunks.get())); + self.chunks.push(self.pod_head.clone()); self.pod_head = chunk(num::next_power_of_two(new_min_chunk_size + 1u), true); @@ -224,7 +224,7 @@ impl Arena { -> (*u8, *u8) { // Allocate a new chunk. let new_min_chunk_size = cmp::max(n_bytes, self.chunk_size()); - self.chunks.set(@Cons(self.head.clone(), self.chunks.get())); + self.chunks.push(self.head.clone()); self.head = chunk(num::next_power_of_two(new_min_chunk_size + 1u), false); diff --git a/src/libcollections/list.rs b/src/libcollections/list.rs index 18da9671419ee..187c74d450e44 100644 --- a/src/libcollections/list.rs +++ b/src/libcollections/list.rs @@ -8,45 +8,102 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A standard, garbage-collected linked list. - use std::container::Container; - -#[deriving(Clone, Eq)] -#[allow(missing_doc)] +use std::fmt; +use std::mem; + +/// A linked list implementation. +/// +/// # Example +/// +/// ```rust +/// use collections::list::{List, Cons, Nil}; +/// +/// let mut list = List::new(); +/// list.push(3); +/// list.push(2); +/// list.push(1); +/// assert_eq!(list, Cons(1, ~Cons(2, ~Cons(3, ~Nil)))); +/// ``` pub enum List { - Cons(T, @List), + /// A node with a value in the linked list. + Cons(T, ~List), + + /// No value. Nil, } -pub struct Items<'a, T> { - priv head: &'a List, - priv next: Option<&'a @List> -} +impl List { + /// Create an empty linked list. + /// + /// ```rust + /// use collections::list::{List, Nil}; + /// + /// let list: List = List::new(); + /// assert_eq!(list, Nil); + /// ``` + #[inline] + pub fn new() -> List { + Nil + } -impl<'a, T> Iterator<&'a T> for Items<'a, T> { - fn next(&mut self) -> Option<&'a T> { - match self.next { - None => match *self.head { - Nil => None, - Cons(ref value, ref tail) => { - self.next = Some(tail); - Some(value) - } - }, - Some(next) => match **next { - Nil => None, - Cons(ref value, ref tail) => { - self.next = Some(tail); - Some(value) - } + /// Pushes a value at the front of the list. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let mut list = List::new(); + /// assert_eq!(list.head(), None); + /// + /// list.push(5); + /// assert_eq!(list.head().unwrap(), &5); + /// ``` + #[inline] + pub fn push(&mut self, value: T) { + *self = Cons(value, ~mem::replace(self, Nil)); + } + + /// Removes the first element of a list, or `None` if empty. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let mut list = List::new(); + /// assert_eq!(list.pop(), None); + /// + /// list.push(5); + /// assert_eq!(list.pop(), Some(5)); + /// ``` + #[inline] + pub fn pop(&mut self) -> Option { + match mem::replace(self, Nil) { + Cons(value, ~tail) => { + *self = tail; + Some(value) } + Nil => None, } } -} -impl List { - /// Returns a forward iterator + /// Provide a forward iterator. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let list = List::from_vec([1, 2, 3]); + /// let mut iter = list.iter(); + /// assert_eq!(iter.next().unwrap(), &1); + /// assert_eq!(iter.next().unwrap(), &2); + /// assert_eq!(iter.next().unwrap(), &3); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] pub fn iter<'a>(&'a self) -> Items<'a, T> { Items { head: self, @@ -54,7 +111,40 @@ impl List { } } - /// Returns the first element of a list + /// Provide a forward iterator that moves elements out of the list. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let list = List::from_vec([1, 2, 3]); + /// let mut iter = list.move_iter(); + /// assert_eq!(iter.next().unwrap(), 1); + /// assert_eq!(iter.next().unwrap(), 2); + /// assert_eq!(iter.next().unwrap(), 3); + /// assert_eq!(iter.next(), None); + /// ``` + #[inline] + pub fn move_iter(self) -> MoveItems { + MoveItems { + head: self, + } + } + + /// Returns the first element of a list. + /// + /// # example + /// + /// ```rust + /// use collections::List; + /// + /// let mut list = List::new(); + /// assert_eq!(list.head(), None); + /// + /// list.push(1); + /// assert_eq!(list.head().unwrap(), &1); + #[inline] pub fn head<'a>(&'a self) -> Option<&'a T> { match *self { Nil => None, @@ -62,53 +152,273 @@ impl List { } } - /// Returns all but the first element of a list - pub fn tail(&self) -> Option<@List> { + /// Returns all but the first element of a list. + /// + /// # example + /// + /// ```rust + /// use collections::list::{List, Cons, Nil}; + /// + /// let mut list = List::new(); + /// assert_eq!(list.tail(), None); + /// + /// list.push(1); + /// assert_eq!(list.tail().unwrap(), &Nil); + /// + /// list.push(2); + /// assert_eq!(list.tail().unwrap(), &Cons(1, ~Nil)); + #[inline] + pub fn tail<'a>(&'a self) -> Option<&'a List> { match *self { Nil => None, - Cons(_, tail) => Some(tail) + Cons(_, ref tail) => Some(&**tail) + } + } +} + +impl List { + /// Create a list from a vector. + /// + /// # Example + /// + /// ```rust + /// use collections::list::{List, Cons, Nil}; + /// + /// let list = List::from_vec([1, 2, 3]); + /// assert_eq!(list, Cons(1, ~Cons(2, ~Cons(3, ~Nil)))); + /// ``` + pub fn from_vec(v: &[T]) -> List { + match v.len() { + 0 => Nil, + _ => { + v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), ~tail)) + } + } + } + + /// Creates a reversed list from an iterator. This is faster than using + /// `FromIterator::from_iterator`. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let v = ~[1, 2, 3]; + /// let list: List = List::from_iterator_rev(&mut v.move_iter()); + /// assert_eq!(list, List::from_vec([3, 2, 1])); + /// ``` + pub fn from_iterator_rev>(iterator: &mut Iter) -> List { + let mut list = List::new(); + + for elt in *iterator { + list.push(elt); + } + + list + } + + /// Appends one list at the end of another. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let a = List::from_vec([1, 2, 3]); + /// let b = List::from_vec([4, 5, 6]); + /// let c = a.append(b); + /// assert_eq!(c, List::from_vec([1, 2, 3, 4, 5, 6])); + /// ``` + pub fn append(self, other: List) -> List { + match (self, other) { + (Nil, other) => other, + (self_, Nil) => self_, + (self_, other) => { + let mut list = List::from_iterator_rev(&mut self_.move_iter()); + + for elt in other.move_iter() { + list.push(elt); + } + + list.reverse(); + + list + } + } + } + + /// Reverses a list in place. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let mut list = List::from_vec([1, 2, 3]); + /// list.reverse(); + /// assert_eq!(list, List::from_vec([3, 2, 1])); + /// ``` + pub fn reverse(&mut self) { + for elt in mem::replace(self, Nil).move_iter() { + self.push(elt); + } + } +} + +impl List { + /// Return true if the list contains a value. + /// + /// # Example + /// + /// ```rust + /// use collections::List; + /// + /// let list = List::from_vec([1, 2, 3]); + /// assert!(list.contains(&2)); + /// assert!(!list.contains(&4)); + /// ``` + pub fn contains(&self, element: &T) -> bool { + self.iter().any(|list_element| list_element == element) + } +} + +impl Clone for List { + fn clone(&self) -> List { + // Contruct the list in reversed order to avoid a stack overflow. + let mut list = List::new(); + + for elt in self.iter() { + list.push(elt.clone()); + } + + list.reverse(); + + list + } +} + +impl Eq for List { + fn eq(&self, other: &List) -> bool { + // Explicitly implement `Eq` to avoid running out of stack while + // comparing lists. + let mut list0 = self; + let mut list1 = other; + + loop { + match *list0 { + Nil => { + match *list1 { + Nil => { return true; } + Cons(_, _) => { return false; } + } + } + Cons(ref v0, ref t0) => { + match *list1 { + Nil => { return false; } + Cons(ref v1, ref t1) => { + if v0 != v1 { return false; } + + list0 = &**t0; + list1 = &**t1; + } + } + } + } } } } impl Container for List { - /// Returns the length of a list fn len(&self) -> uint { self.iter().len() } - /// Returns true if the list is empty fn is_empty(&self) -> bool { match *self { Nil => true, _ => false } } } -impl List { - /// Returns true if a list contains an element with the given value - pub fn contains(&self, element: T) -> bool { - self.iter().any(|list_element| *list_element == element) +impl FromIterator for List { + fn from_iterator>(iterator: &mut Iter) -> List { + let mut list = List::from_iterator_rev(iterator); + list.reverse(); + list } } -impl List { - /// Create a list from a vector - pub fn from_vec(v: &[T]) -> List { - match v.len() { - 0 => Nil, - _ => v.rev_iter().fold(Nil, |tail, value: &T| Cons(value.clone(), @tail)) +impl Extendable for List { + fn extend>(&mut self, iterator: &mut Iter) { + let mut list = List::from_iterator_rev(iterator); + + for elt in self.iter() { + list.push(elt.clone()); + } + + list.reverse(); + + *self = list; + } +} + +impl fmt::Show for List { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + try!(write!(f.buf, "[")); + let mut is_first = true; + for x in self.iter() { + if is_first { + is_first = false; + } else { + try!(write!(f.buf, ", ")); + } + try!(write!(f.buf, "{}", *x)) } + write!(f.buf, "]") } +} - /// Appends one list to another, returning a new list - pub fn append(&self, other: List) -> List { - match other { - Nil => return self.clone(), - _ => match *self { - Nil => return other, - Cons(ref value, tail) => Cons(value.clone(), @tail.append(other)) +/// A linked list iterator. See `List::iter` for a usage example. +pub struct Items<'a, T> { + priv head: &'a List, + priv next: Option<&'a ~List> +} + +impl<'a, T> Iterator<&'a T> for Items<'a, T> { + fn next(&mut self) -> Option<&'a T> { + match self.next { + None => { + match *self.head { + Nil => None, + Cons(ref value, ref tail) => { + self.next = Some(tail); + Some(value) + } + } + } + Some(next) => { + match **next { + Nil => None, + Cons(ref value, ref tail) => { + self.next = Some(tail); + Some(value) + } + } } } } +} - /// Push one element into the front of a list, returning a new list - pub fn unshift(&self, element: T) -> List { - Cons(element, @(self.clone())) +/// A linked list iterator that moves the elements out of the list. See +/// `List::move_iter` for a usage example. +pub struct MoveItems { + priv head: List, +} + +impl Iterator for MoveItems { + fn next(&mut self) -> Option { + match mem::replace(&mut self.head, Nil) { + Nil => None, + Cons(value, tail) => { + self.head = *tail; + Some(value) + } + } } } @@ -203,12 +513,12 @@ mod tests { #[test] fn test_contains() { let empty = Nil::; - assert!((!empty.contains(5))); + assert!((!empty.contains(&5))); let list = List::from_vec([5, 8, 6]); - assert!((list.contains(5))); - assert!((!list.contains(7))); - assert!((list.contains(8))); + assert!((list.contains(&5))); + assert!((!list.contains(&7))); + assert!((list.contains(&8))); } #[test] @@ -227,11 +537,10 @@ mod tests { } #[test] - fn test_unshift() { - let list = List::from_vec([1]); - let new_list = list.unshift(0); - assert_eq!(list.len(), 1u); - assert_eq!(new_list.len(), 2u); - assert!(new_list == List::from_vec([0, 1])); + fn test_push() { + let mut list = List::from_vec([1]); + list.push(0); + assert_eq!(list.len(), 2); + assert!(list == List::from_vec([0, 1])); } } diff --git a/src/test/bench/task-perf-alloc-unwind.rs b/src/test/bench/task-perf-alloc-unwind.rs index e0938a8ae0310..608ba00e9844f 100644 --- a/src/test/bench/task-perf-alloc-unwind.rs +++ b/src/test/bench/task-perf-alloc-unwind.rs @@ -13,11 +13,15 @@ extern crate collections; extern crate time; -use collections::list::{List, Cons, Nil}; use time::precise_time_s; use std::os; use std::task; +#[deriving(Clone)] +enum List { + Nil, Cons(T, @List) +} + enum UniqueList { ULNil, ULCons(~UniqueList) } diff --git a/src/test/run-pass/log-knows-the-names-of-variants-in-std.rs b/src/test/run-pass/log-knows-the-names-of-variants-in-std.rs index 0129740252ca1..36fbc364b9d82 100644 --- a/src/test/run-pass/log-knows-the-names-of-variants-in-std.rs +++ b/src/test/run-pass/log-knows-the-names-of-variants-in-std.rs @@ -25,7 +25,7 @@ fn check_log(exp: ~str, v: T) { pub fn main() { let x = List::from_vec([a(22u), b(~"hi")]); - let exp = ~"Cons(a(22u), @Cons(b(~\"hi\"), @Nil))"; + let exp = ~"Cons(a(22u), ~Cons(b(~\"hi\"), ~Nil))"; let act = format!("{:?}", x); assert!(act == exp); check_log(exp, x); diff --git a/src/test/run-pass/non-boolean-pure-fns.rs b/src/test/run-pass/non-boolean-pure-fns.rs deleted file mode 100644 index 66bb2e702bea3..0000000000000 --- a/src/test/run-pass/non-boolean-pure-fns.rs +++ /dev/null @@ -1,36 +0,0 @@ -// ignore-fast - -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#[feature(managed_boxes)]; - -extern crate collections; - -use collections::list::{List, Cons, Nil}; - -fn pure_length_go(ls: @List, acc: uint) -> uint { - match *ls { Nil => { acc } Cons(_, tl) => { pure_length_go(tl, acc + 1u) } } -} - -fn pure_length(ls: @List) -> uint { pure_length_go(ls, 0u) } - -fn nonempty_list(ls: @List) -> bool { pure_length(ls) > 0u } - -fn safe_head(ls: @List) -> T { - assert!(!ls.is_empty()); - return ls.head().unwrap().clone(); -} - -pub fn main() { - let mylist = @Cons(@1u, @Nil); - assert!((nonempty_list(mylist))); - assert_eq!(*safe_head(mylist), 1u); -}