diff options
| author | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-06 16:21:02 -0700 |
|---|---|---|
| committer | Erick Tryzelaar <erick.tryzelaar@gmail.com> | 2013-08-06 16:21:02 -0700 |
| commit | 5eaa4d1d2f6eafc4233892d3d1dafb0d05799ac3 (patch) | |
| tree | 3ee757ce4806cf7686f0508952149f2a75d0d0f3 /src/libstd | |
| parent | 5e7b6662502a82b6f1a789277d3dc2e68aa4eb13 (diff) | |
| parent | 6972eb4cd7702a343a7e79c4a57522d0de763327 (diff) | |
| download | rust-5eaa4d1d2f6eafc4233892d3d1dafb0d05799ac3.tar.gz rust-5eaa4d1d2f6eafc4233892d3d1dafb0d05799ac3.zip | |
Merge remote-tracking branch 'remotes/origin/master' into remove-str-trailing-nulls
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/at_vec.rs | 6 | ||||
| -rw-r--r-- | src/libstd/either.rs | 366 | ||||
| -rw-r--r-- | src/libstd/hashmap.rs | 54 | ||||
| -rw-r--r-- | src/libstd/io.rs | 2 | ||||
| -rw-r--r-- | src/libstd/iterator.rs | 65 | ||||
| -rw-r--r-- | src/libstd/local_data.rs | 14 | ||||
| -rw-r--r-- | src/libstd/num/strconv.rs | 2 | ||||
| -rw-r--r-- | src/libstd/num/uint.rs | 24 | ||||
| -rw-r--r-- | src/libstd/option.rs | 258 | ||||
| -rw-r--r-- | src/libstd/os.rs | 6 | ||||
| -rw-r--r-- | src/libstd/ptr.rs | 7 | ||||
| -rw-r--r-- | src/libstd/rand.rs | 4 | ||||
| -rw-r--r-- | src/libstd/result.rs | 357 | ||||
| -rw-r--r-- | src/libstd/rt/io/flate.rs | 4 | ||||
| -rw-r--r-- | src/libstd/rt/io/mod.rs | 36 | ||||
| -rw-r--r-- | src/libstd/rt/kill.rs | 13 | ||||
| -rw-r--r-- | src/libstd/rt/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/rt/task.rs | 4 | ||||
| -rw-r--r-- | src/libstd/rt/test.rs | 4 | ||||
| -rw-r--r-- | src/libstd/rt/util.rs | 4 | ||||
| -rw-r--r-- | src/libstd/rt/uv/net.rs | 6 | ||||
| -rw-r--r-- | src/libstd/rt/uv/uvio.rs | 2 | ||||
| -rw-r--r-- | src/libstd/str.rs | 6 | ||||
| -rw-r--r-- | src/libstd/task/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/task/spawn.rs | 104 | ||||
| -rw-r--r-- | src/libstd/trie.rs | 94 | ||||
| -rw-r--r-- | src/libstd/vec.rs | 68 |
27 files changed, 831 insertions, 683 deletions
diff --git a/src/libstd/at_vec.rs b/src/libstd/at_vec.rs index 4ece53d0e7f..a84f3137bbd 100644 --- a/src/libstd/at_vec.rs +++ b/src/libstd/at_vec.rs @@ -78,10 +78,8 @@ pub fn build<A>(builder: &fn(push: &fn(v: A))) -> @[A] { * onto the vector being constructed. */ #[inline] -pub fn build_sized_opt<A>(size: Option<uint>, - builder: &fn(push: &fn(v: A))) - -> @[A] { - build_sized(size.get_or_default(4), builder) +pub fn build_sized_opt<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> @[A] { + build_sized(size.unwrap_or_default(4), builder) } // Appending diff --git a/src/libstd/either.rs b/src/libstd/either.rs index 6bdc45d7204..cfaef550c6f 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -23,29 +23,102 @@ use str::StrSlice; use vec; use vec::{OwnedVector, ImmutableVector}; -/// The either type +/// `Either` is a type that represents one of two alternatives #[deriving(Clone, Eq)] -pub enum Either<T, U> { - Left(T), - Right(U) +pub enum Either<L, R> { + Left(L), + Right(R) } -/// Applies a function based on the given either value -/// -/// If `value` is left(T) then `f_left` is applied to its contents, if -/// `value` is right(U) then `f_right` is applied to its contents, and the -/// result is returned. -#[inline] -pub fn either<T, U, V>(f_left: &fn(&T) -> V, - f_right: &fn(&U) -> V, value: &Either<T, U>) -> V { - match *value { - Left(ref l) => f_left(l), - Right(ref r) => f_right(r) +impl<L, R> Either<L, R> { + /// Applies a function based on the given either value + /// + /// If `value` is `Left(L)` then `f_left` is applied to its contents, if + /// `value` is `Right(R)` then `f_right` is applied to its contents, and the + /// result is returned. + #[inline] + pub fn either<T>(&self, f_left: &fn(&L) -> T, f_right: &fn(&R) -> T) -> T { + match *self { + Left(ref l) => f_left(l), + Right(ref r) => f_right(r) + } + } + + /// Flips between left and right of a given `Either` + #[inline] + pub fn flip(self) -> Either<R, L> { + match self { + Right(r) => Left(r), + Left(l) => Right(l) + } + } + + /// Converts a `Either` to a `Result` + /// + /// Converts an `Either` type to a `Result` type, making the "right" choice + /// an `Ok` result, and the "left" choice a `Err` + #[inline] + pub fn to_result(self) -> Result<R, L> { + match self { + Right(r) => result::Ok(r), + Left(l) => result::Err(l) + } + } + + /// Checks whether the given value is a `Left` + #[inline] + pub fn is_left(&self) -> bool { + match *self { + Left(_) => true, + _ => false + } + } + + /// Checks whether the given value is a `Right` + #[inline] + pub fn is_right(&self) -> bool { + match *self { + Right(_) => true, + _ => false + } + } + + /// Retrieves the value from a `Left`. + /// Fails with a specified reason if the `Either` is `Right`. + #[inline] + pub fn expect_left(self, reason: &str) -> L { + match self { + Left(x) => x, + Right(_) => fail!(reason.to_owned()) + } + } + + /// Retrieves the value from a `Left`. Fails if the `Either` is `Right`. + #[inline] + pub fn unwrap_left(self) -> L { + self.expect_left("called Either::unwrap_left()` on `Right` value") + } + + /// Retrieves the value from a `Right`. + /// Fails with a specified reason if the `Either` is `Left`. + #[inline] + pub fn expect_right(self, reason: &str) -> R { + match self { + Right(x) => x, + Left(_) => fail!(reason.to_owned()) + } + } + + /// Retrieves the value from a `Right`. Fails if the `Either` is `Left`. + #[inline] + pub fn unwrap_right(self) -> R { + self.expect_right("called Either::unwrap_right()` on `Left` value") } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the left values -pub fn lefts<T:Clone,U>(eithers: &[Either<T, U>]) -> ~[T] { +pub fn lefts<L: Clone, R>(eithers: &[Either<L, R>]) -> ~[L] { do vec::build_sized(eithers.len()) |push| { for elt in eithers.iter() { match *elt { @@ -56,8 +129,9 @@ pub fn lefts<T:Clone,U>(eithers: &[Either<T, U>]) -> ~[T] { } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the right values -pub fn rights<T, U: Clone>(eithers: &[Either<T, U>]) -> ~[U] { +pub fn rights<L, R: Clone>(eithers: &[Either<L, R>]) -> ~[R] { do vec::build_sized(eithers.len()) |push| { for elt in eithers.iter() { match *elt { @@ -68,13 +142,14 @@ pub fn rights<T, U: Clone>(eithers: &[Either<T, U>]) -> ~[U] { } } +// FIXME: #8228 Replaceable by an external iterator? /// Extracts from a vector of either all the left values and right values /// /// Returns a structure containing a vector of left values and a vector of /// right values. -pub fn partition<T, U>(eithers: ~[Either<T, U>]) -> (~[T], ~[U]) { - let mut lefts: ~[T] = ~[]; - let mut rights: ~[U] = ~[]; +pub fn partition<L, R>(eithers: ~[Either<L, R>]) -> (~[L], ~[R]) { + let mut lefts: ~[L] = ~[]; + let mut rights: ~[R] = ~[]; for elt in eithers.consume_iter() { match elt { Left(l) => lefts.push(l), @@ -84,196 +159,101 @@ pub fn partition<T, U>(eithers: ~[Either<T, U>]) -> (~[T], ~[U]) { return (lefts, rights); } -/// Flips between left and right of a given either -#[inline] -pub fn flip<T, U>(eith: Either<T, U>) -> Either<U, T> { - match eith { - Right(r) => Left(r), - Left(l) => Right(l) - } -} +#[cfg(test)] +mod tests { + use super::*; -/// Converts either::t to a result::t -/// -/// Converts an `either` type to a `result` type, making the "right" choice -/// an ok result, and the "left" choice a fail -#[inline] -pub fn to_result<T, U>(eith: Either<T, U>) -> Result<U, T> { - match eith { - Right(r) => result::Ok(r), - Left(l) => result::Err(l) + #[test] + fn test_either_left() { + let val = Left(10); + fn f_left(x: &int) -> bool { *x == 10 } + fn f_right(_x: &uint) -> bool { false } + assert!(val.either(f_left, f_right)); } -} -/// Checks whether the given value is a left -#[inline] -pub fn is_left<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Left(_) => true, - _ => false + #[test] + fn test_either_right() { + let val = Right(10u); + fn f_left(_x: &int) -> bool { false } + fn f_right(x: &uint) -> bool { *x == 10u } + assert!(val.either(f_left, f_right)); } -} -/// Checks whether the given value is a right -#[inline] -pub fn is_right<T, U>(eith: &Either<T, U>) -> bool { - match *eith { - Right(_) => true, - _ => false + #[test] + fn test_lefts() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let result = lefts(input); + assert_eq!(result, ~[10, 12, 14]); } -} -/// Retrieves the value in the left branch. -/// Fails with a specified reason if the either is Right. -#[inline] -pub fn expect_left<T,U>(eith: Either<T,U>, reason: &str) -> T { - match eith { - Left(x) => x, - Right(_) => fail!(reason.to_owned()) + #[test] + fn test_lefts_none() { + let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; + let result = lefts(input); + assert_eq!(result.len(), 0u); } -} -/// Retrieves the value in the left branch. Fails if the either is Right. -#[inline] -pub fn unwrap_left<T,U>(eith: Either<T,U>) -> T { - expect_left(eith, "either::unwrap_left Right") -} - -/// Retrieves the value in the right branch. -/// Fails with a specified reason if the either is Left. -#[inline] -pub fn expect_right<T,U>(eith: Either<T,U>, reason: &str) -> U { - match eith { - Right(x) => x, - Left(_) => fail!(reason.to_owned()) + #[test] + fn test_lefts_empty() { + let input: ~[Either<int, int>] = ~[]; + let result = lefts(input); + assert_eq!(result.len(), 0u); } -} -/// Retrieves the value in the right branch. Fails if the either is Left. -pub fn unwrap_right<T,U>(eith: Either<T,U>) -> U { - expect_right(eith, "either::unwrap_right Left") -} - -impl<T, U> Either<T, U> { - #[inline] - pub fn either<V>(&self, f_left: &fn(&T) -> V, f_right: &fn(&U) -> V) -> V { - either(f_left, f_right, self) + #[test] + fn test_rights() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let result = rights(input); + assert_eq!(result, ~[11, 13]); } - #[inline] - pub fn flip(self) -> Either<U, T> { flip(self) } - - #[inline] - pub fn to_result(self) -> Result<U, T> { to_result(self) } - - #[inline] - pub fn is_left(&self) -> bool { is_left(self) } - - #[inline] - pub fn is_right(&self) -> bool { is_right(self) } - - #[inline] - pub fn expect_left(self, reason: &str) -> T { expect_left(self, reason) } - - #[inline] - pub fn unwrap_left(self) -> T { unwrap_left(self) } - - #[inline] - pub fn expect_right(self, reason: &str) -> U { expect_right(self, reason) } - - #[inline] - pub fn unwrap_right(self) -> U { unwrap_right(self) } -} - -#[test] -fn test_either_left() { - let val = Left(10); - fn f_left(x: &int) -> bool { *x == 10 } - fn f_right(_x: &uint) -> bool { false } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_either_right() { - let val = Right(10u); - fn f_left(_x: &int) -> bool { false } - fn f_right(x: &uint) -> bool { *x == 10u } - assert!((either(f_left, f_right, &val))); -} - -#[test] -fn test_lefts() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = lefts(input); - assert_eq!(result, ~[10, 12, 14]); -} - -#[test] -fn test_lefts_none() { - let input: ~[Either<int, int>] = ~[Right(10), Right(10)]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_lefts_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = lefts(input); - assert_eq!(result.len(), 0u); -} - -#[test] -fn test_rights() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = rights(input); - assert_eq!(result, ~[11, 13]); -} + #[test] + fn test_rights_none() { + let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; + let result = rights(input); + assert_eq!(result.len(), 0u); + } -#[test] -fn test_rights_none() { - let input: ~[Either<int, int>] = ~[Left(10), Left(10)]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} + #[test] + fn test_rights_empty() { + let input: ~[Either<int, int>] = ~[]; + let result = rights(input); + assert_eq!(result.len(), 0u); + } -#[test] -fn test_rights_empty() { - let input: ~[Either<int, int>] = ~[]; - let result = rights(input); - assert_eq!(result.len(), 0u); -} + #[test] + fn test_partition() { + let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts[0], 10); + assert_eq!(lefts[1], 12); + assert_eq!(lefts[2], 14); + assert_eq!(rights[0], 11); + assert_eq!(rights[1], 13); + } -#[test] -fn test_partition() { - let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts[0], 10); - assert_eq!(lefts[1], 12); - assert_eq!(lefts[2], 14); - assert_eq!(rights[0], 11); - assert_eq!(rights[1], 13); -} + #[test] + fn test_partition_no_lefts() { + let input: ~[Either<int, int>] = ~[Right(10), Right(11)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 0u); + assert_eq!(rights.len(), 2u); + } -#[test] -fn test_partition_no_lefts() { - let input: ~[Either<int, int>] = ~[Right(10), Right(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 2u); -} + #[test] + fn test_partition_no_rights() { + let input: ~[Either<int, int>] = ~[Left(10), Left(11)]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 2u); + assert_eq!(rights.len(), 0u); + } -#[test] -fn test_partition_no_rights() { - let input: ~[Either<int, int>] = ~[Left(10), Left(11)]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 2u); - assert_eq!(rights.len(), 0u); -} + #[test] + fn test_partition_empty() { + let input: ~[Either<int, int>] = ~[]; + let (lefts, rights) = partition(input); + assert_eq!(lefts.len(), 0u); + assert_eq!(rights.len(), 0u); + } -#[test] -fn test_partition_empty() { - let input: ~[Either<int, int>] = ~[]; - let (lefts, rights) = partition(input); - assert_eq!(lefts.len(), 0u); - assert_eq!(rights.len(), 0u); } diff --git a/src/libstd/hashmap.rs b/src/libstd/hashmap.rs index 658f854c50d..fbc471c0ae0 100644 --- a/src/libstd/hashmap.rs +++ b/src/libstd/hashmap.rs @@ -19,7 +19,8 @@ use container::{Container, Mutable, Map, MutableMap, Set, MutableSet}; use clone::Clone; use cmp::{Eq, Equiv}; use hash::Hash; -use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, Chain, range}; +use iterator::{Iterator, IteratorUtil, FromIterator, Extendable, range}; +use iterator::{FilterMap, Chain, Repeat, Zip}; use num; use option::{None, Option, Some}; use rand::RngUtil; @@ -712,10 +713,12 @@ impl<T:Hash + Eq> HashSet<T> { } /// Visit the values representing the difference - pub fn difference_iter<'a>(&'a self, other: &'a HashSet<T>) - -> SetAlgebraIter<'a, T> { - EnvFilterIterator{iter: self.iter(), env: other, - filter: |elt, other| !other.contains(elt) } + pub fn difference_iter<'a>(&'a self, other: &'a HashSet<T>) -> SetAlgebraIter<'a, T> { + Repeat::new(other) + .zip(self.iter()) + .filter_map(|(other, elt)| { + if !other.contains(elt) { Some(elt) } else { None } + }) } /// Visit the values representing the symmetric difference @@ -727,8 +730,11 @@ impl<T:Hash + Eq> HashSet<T> { /// Visit the values representing the intersection pub fn intersection_iter<'a>(&'a self, other: &'a HashSet<T>) -> SetAlgebraIter<'a, T> { - EnvFilterIterator{iter: self.iter(), env: other, - filter: |elt, other| other.contains(elt) } + Repeat::new(other) + .zip(self.iter()) + .filter_map(|(other, elt)| { + if other.contains(elt) { Some(elt) } else { None } + }) } /// Visit the values representing the union @@ -756,38 +762,12 @@ impl<K: Eq + Hash, T: Iterator<K>> Extendable<K, T> for HashSet<K> { } } -// FIXME #7814: use std::iterator::FilterIterator -/// Building block for Set operation iterators -pub struct EnvFilterIterator<A, Env, I> { - priv env: Env, - priv filter: &'static fn(&A, Env) -> bool, - priv iter: I, -} - -impl<'self, A, Env: Clone, I: Iterator<&'self A>> Iterator<&'self A> - for EnvFilterIterator<A, Env, I> { - #[inline] - fn next(&mut self) -> Option<&'self A> { - loop { - match self.iter.next() { - Some(elt) => if (self.filter)(elt, self.env.clone()) { - return Some(elt) - }, - None => return None, - } - } - } - - #[inline] - fn size_hint(&self) -> (uint, Option<uint>) { - let (_, upper) = self.iter.size_hint(); - (0, upper) - } -} - +// `Repeat` is used to feed the filter closure an explicit capture +// of a reference to the other set /// Set operations iterator pub type SetAlgebraIter<'self, T> = - EnvFilterIterator<T, &'self HashSet<T>, HashSetIterator<'self, T>>; + FilterMap<'static,(&'self HashSet<T>, &'self T), &'self T, + Zip<Repeat<&'self HashSet<T>>,HashSetIterator<'self,T>>>; #[cfg(test)] diff --git a/src/libstd/io.rs b/src/libstd/io.rs index 1c2fc5db443..07572d60917 100644 --- a/src/libstd/io.rs +++ b/src/libstd/io.rs @@ -1042,7 +1042,7 @@ pub fn stdin() -> @Reader { pub fn file_reader(path: &Path) -> Result<@Reader, ~str> { let f = do path.to_c_str().with_ref |pathbuf| { - do "r".to_c_str().with_ref |modebuf| { + do "rb".to_c_str().with_ref |modebuf| { unsafe { libc::fopen(pathbuf, modebuf as *libc::c_char) } } }; diff --git a/src/libstd/iterator.rs b/src/libstd/iterator.rs index 0769aa6a764..56a0dca5667 100644 --- a/src/libstd/iterator.rs +++ b/src/libstd/iterator.rs @@ -82,6 +82,17 @@ pub trait DoubleEndedIteratorUtil { /// In the future these will be default methods instead of a utility trait. impl<A, T: DoubleEndedIterator<A>> DoubleEndedIteratorUtil for T { /// Flip the direction of the iterator + /// + /// The inverted iterator flips the ends on an iterator that can already + /// be iterated from the front and from the back. + /// + /// + /// If the iterator also implements RandomAccessIterator, the inverted + /// iterator is also random access, with the indices starting at the back + /// of the original iterator. + /// + /// Note: Random access with inverted indices still only applies to the first + /// `uint::max_value` elements of the original iterator. #[inline] fn invert(self) -> Invert<T> { Invert{iter: self} @@ -106,6 +117,16 @@ impl<A, T: DoubleEndedIterator<A>> DoubleEndedIterator<A> for Invert<T> { fn next_back(&mut self) -> Option<A> { self.iter.next() } } +impl<A, T: DoubleEndedIterator<A> + RandomAccessIterator<A>> RandomAccessIterator<A> + for Invert<T> { + #[inline] + fn indexable(&self) -> uint { self.iter.indexable() } + #[inline] + fn idx(&self, index: uint) -> Option<A> { + self.iter.idx(self.indexable() - index - 1) + } +} + /// Iterator adaptors provided for every `Iterator` implementation. The adaptor objects are also /// implementations of the `Iterator` trait. /// @@ -1555,6 +1576,39 @@ impl<A: Add<A, A> + Clone> Iterator<A> for Counter<A> { } } +/// An iterator that repeats an element endlessly +#[deriving(Clone, DeepClone)] +pub struct Repeat<A> { + priv element: A +} + +impl<A: Clone> Repeat<A> { + /// Create a new `Repeat` that enlessly repeats the element `elt`. + #[inline] + pub fn new(elt: A) -> Repeat<A> { + Repeat{element: elt} + } +} + +impl<A: Clone> Iterator<A> for Repeat<A> { + #[inline] + fn next(&mut self) -> Option<A> { self.idx(0) } + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { (uint::max_value, None) } +} + +impl<A: Clone> DoubleEndedIterator<A> for Repeat<A> { + #[inline] + fn next_back(&mut self) -> Option<A> { self.idx(0) } +} + +impl<A: Clone> RandomAccessIterator<A> for Repeat<A> { + #[inline] + fn indexable(&self) -> uint { uint::max_value } + #[inline] + fn idx(&self, _: uint) -> Option<A> { Some(self.element.clone()) } +} + #[cfg(test)] mod tests { use super::*; @@ -2018,6 +2072,17 @@ mod tests { } #[test] + fn test_random_access_invert() { + let xs = [1, 2, 3, 4, 5]; + check_randacc_iter(xs.iter().invert(), xs.len()); + let mut it = xs.iter().invert(); + it.next(); + it.next_back(); + it.next(); + check_randacc_iter(it, xs.len() - 3); + } + + #[test] fn test_random_access_zip() { let xs = [1, 2, 3, 4, 5]; let ys = [7, 9, 11]; diff --git a/src/libstd/local_data.rs b/src/libstd/local_data.rs index 537289c8dd6..c2a60e1c0e9 100644 --- a/src/libstd/local_data.rs +++ b/src/libstd/local_data.rs @@ -112,14 +112,14 @@ fn test_tls_multitask() { // TLS shouldn't carry over. assert!(get(my_key, |k| k.map(|&k| *k)).is_none()); set(my_key, @~"child data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == + assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"child data"); // should be cleaned up for us } // Must work multiple times - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"parent data"); } #[test] @@ -127,14 +127,14 @@ fn test_tls_overwrite() { static my_key: Key<@~str> = &Key; set(my_key, @~"first data"); set(my_key, @~"next data"); // Shouldn't leak. - assert!(*(get(my_key, |k| k.map(|&k| *k)).get()) == ~"next data"); + assert!(*(get(my_key, |k| k.map(|&k| *k)).unwrap()) == ~"next data"); } #[test] fn test_tls_pop() { static my_key: Key<@~str> = &Key; set(my_key, @~"weasel"); - assert!(*(pop(my_key).get()) == ~"weasel"); + assert!(*(pop(my_key).unwrap()) == ~"weasel"); // Pop must remove the data from the map. assert!(pop(my_key).is_none()); } @@ -155,7 +155,7 @@ fn test_tls_modify() { None => fail!("missing value") } }); - assert!(*(pop(my_key).get()) == ~"next data"); + assert!(*(pop(my_key).unwrap()) == ~"next data"); } #[test] diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 722af828d5c..7ab3c81b61f 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -726,4 +726,4 @@ mod bench { float::to_str(rng.gen()); } } -} \ No newline at end of file +} diff --git a/src/libstd/num/uint.rs b/src/libstd/num/uint.rs index 275a72d6ecc..86bc98e53fc 100644 --- a/src/libstd/num/uint.rs +++ b/src/libstd/num/uint.rs @@ -70,30 +70,6 @@ pub fn div_round(x: uint, y: uint) -> uint { /// pub fn div_floor(x: uint, y: uint) -> uint { return x / y; } -/// -/// Iterate over the range [`lo`..`hi`), or stop when requested -/// -/// # Arguments -/// -/// * lo - The integer at which to start the loop (included) -/// * hi - The integer at which to stop the loop (excluded) -/// * it - A block to execute with each consecutive integer of the range. -/// Return `true` to continue, `false` to stop. -/// -/// # Return value -/// -/// `true` If execution proceeded correctly, `false` if it was interrupted, -/// that is if `it` returned `false` at any point. -/// -pub fn iterate(lo: uint, hi: uint, it: &fn(uint) -> bool) -> bool { - let mut i = lo; - while i < hi { - if (!it(i)) { return false; } - i += 1u; - } - return true; -} - impl iter::Times for uint { #[inline] /// diff --git a/src/libstd/option.rs b/src/libstd/option.rs index 417251d3740..ea1bddcdb4b 100644 --- a/src/libstd/option.rs +++ b/src/libstd/option.rs @@ -47,7 +47,8 @@ use ops::Add; use util; use num::Zero; use iterator::Iterator; -use str::StrSlice; +use str::{StrSlice, OwnedStr}; +use to_str::ToStr; use clone::DeepClone; /// The option type @@ -85,22 +86,37 @@ impl<T:Ord> Ord for Option<T> { } } -impl<T:Clone+Add<T,T>> Add<Option<T>, Option<T>> for Option<T> { +impl<T: Add<T, T>> Add<Option<T>, Option<T>> for Option<T> { #[inline] fn add(&self, other: &Option<T>) -> Option<T> { match (&*self, &*other) { (&None, &None) => None, - (_, &None) => (*self).clone(), - (&None, _) => (*other).clone(), + (_, &None) => None, + (&None, _) => None, (&Some(ref lhs), &Some(ref rhs)) => Some(*lhs + *rhs) } } } +// FIXME: #8242 implementing manually because deriving doesn't work for some reason +impl<T: ToStr> ToStr for Option<T> { + fn to_str(&self) -> ~str { + match *self { + Some(ref x) => { + let mut s = ~"Some("; + s.push_str(x.to_str()); + s.push_str(")"); + s + } + None => ~"None" + } + } +} + impl<T> Option<T> { /// Return an iterator over the possibly contained value #[inline] - pub fn iter<'r>(&'r self) -> OptionIterator<'r, T> { + pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> { match *self { Some(ref x) => OptionIterator{opt: Some(x)}, None => OptionIterator{opt: None} @@ -109,13 +125,19 @@ impl<T> Option<T> { /// Return a mutable iterator over the possibly contained value #[inline] - pub fn mut_iter<'r>(&'r mut self) -> OptionMutIterator<'r, T> { + pub fn mut_iter<'r>(&'r mut self) -> OptionIterator<&'r mut T> { match *self { - Some(ref mut x) => OptionMutIterator{opt: Some(x)}, - None => OptionMutIterator{opt: None} + Some(ref mut x) => OptionIterator{opt: Some(x)}, + None => OptionIterator{opt: None} } } + /// Return a consuming iterator over the possibly contained value + #[inline] + pub fn consume(self) -> OptionIterator<T> { + OptionIterator{opt: self} + } + /// Returns true if the option equals `None` #[inline] pub fn is_none(&self) -> bool { @@ -148,8 +170,7 @@ impl<T> Option<T> { /// Update an optional value by optionally running its content by reference /// through a function that returns an option. #[inline] - pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) - -> Option<U> { + pub fn chain_ref<'a, U>(&'a self, f: &fn(x: &'a T) -> Option<U>) -> Option<U> { match *self { Some(ref x) => f(x), None => None @@ -159,8 +180,7 @@ impl<T> Option<T> { /// Update an optional value by optionally running its content by mut reference /// through a function that returns an option. #[inline] - pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) - -> Option<U> { + pub fn chain_mut_ref<'a, U>(&'a mut self, f: &fn(x: &'a mut T) -> Option<U>) -> Option<U> { match *self { Some(ref mut x) => f(x), None => None @@ -256,132 +276,105 @@ impl<T> Option<T> { } } - /** - Gets an immutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ + /// Gets an immutable reference to the value inside an option. + /// + /// # Failure + /// + /// Fails if the value equals `None` + /// + /// # Safety note + /// + /// In general, because this function may fail, its use is discouraged + /// (calling `get` on `None` is akin to dereferencing a null pointer). + /// Instead, prefer to use pattern matching and handle the `None` + /// case explicitly. #[inline] pub fn get_ref<'a>(&'a self) -> &'a T { match *self { - Some(ref x) => x, - None => fail!("option::get_ref `None`"), + Some(ref x) => x, + None => fail!("called `Option::get_ref()` on a `None` value"), } } - /** - Gets a mutable reference to the value inside an option. - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ + /// Gets a mutable reference to the value inside an option. + /// + /// # Failure + /// + /// Fails if the value equals `None` + /// + /// # Safety note + /// + /// In general, because this function may fail, its use is discouraged + /// (calling `get` on `None` is akin to dereferencing a null pointer). + /// Instead, prefer to use pattern matching and handle the `None` + /// case explicitly. #[inline] pub fn get_mut_ref<'a>(&'a mut self) -> &'a mut T { match *self { - Some(ref mut x) => x, - None => fail!("option::get_mut_ref `None`"), + Some(ref mut x) => x, + None => fail!("called `Option::get_mut_ref()` on a `None` value"), } } + /// Moves a value out of an option type and returns it. + /// + /// Useful primarily for getting strings, vectors and unique pointers out + /// of option types without copying them. + /// + /// # Failure + /// + /// Fails if the value equals `None`. + /// + /// # Safety note + /// + /// In general, because this function may fail, its use is discouraged. + /// Instead, prefer to use pattern matching and handle the `None` + /// case explicitly. #[inline] pub fn unwrap(self) -> T { - /*! - Moves a value out of an option type and returns it. - - Useful primarily for getting strings, vectors and unique pointers out - of option types without copying them. - - # Failure - - Fails if the value equals `None`. - - # Safety note - - In general, because this function may fail, its use is discouraged. - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ match self { - Some(x) => x, - None => fail!("option::unwrap `None`"), + Some(x) => x, + None => fail!("called `Option::unwrap()` on a `None` value"), } } - /** - * The option dance. Moves a value out of an option type and returns it, - * replacing the original with `None`. - * - * # Failure - * - * Fails if the value equals `None`. - */ + /// The option dance. Moves a value out of an option type and returns it, + /// replacing the original with `None`. + /// + /// # Failure + /// + /// Fails if the value equals `None`. #[inline] pub fn take_unwrap(&mut self) -> T { - if self.is_none() { fail!("option::take_unwrap `None`") } + if self.is_none() { + fail!("called `Option::take_unwrap()` on a `None` value") + } self.take().unwrap() } - /** - * Gets the value out of an option, printing a specified message on - * failure - * - * # Failure - * - * Fails if the value equals `None` - */ + /// Gets the value out of an option, printing a specified message on + /// failure + /// + /// # Failure + /// + /// Fails if the value equals `None` #[inline] pub fn expect(self, reason: &str) -> T { match self { - Some(val) => val, - None => fail!(reason.to_owned()), + Some(val) => val, + None => fail!(reason.to_owned()), } } - /** - Gets the value out of an option - - # Failure - - Fails if the value equals `None` - - # Safety note - - In general, because this function may fail, its use is discouraged - (calling `get` on `None` is akin to dereferencing a null pointer). - Instead, prefer to use pattern matching and handle the `None` - case explicitly. - */ + /// Returns the contained value or a default #[inline] - pub fn get(self) -> T { + pub fn unwrap_or_default(self, def: T) -> T { match self { - Some(x) => return x, - None => fail!("option::get `None`") + Some(x) => x, + None => def } } - /// Returns the contained value or a default - #[inline] - pub fn get_or_default(self, def: T) -> T { - match self { Some(x) => x, None => def } - } - /// Applies a function zero or more times until the result is `None`. #[inline] pub fn while_some(self, blk: &fn(v: T) -> Option<T>) { @@ -395,12 +388,21 @@ impl<T> Option<T> { impl<T:Zero> Option<T> { /// Returns the contained value or zero (for this type) #[inline] - pub fn get_or_zero(self) -> T { + pub fn unwrap_or_zero(self) -> T { match self { Some(x) => x, None => Zero::zero() } } + + /// Returns self or `Some(zero)` (for this type) + #[inline] + pub fn or_zero(self) -> Option<T> { + match self { + None => Some(Zero::zero()), + x => x + } + } } impl<T> Zero for Option<T> { @@ -408,34 +410,18 @@ impl<T> Zero for Option<T> { fn is_zero(&self) -> bool { self.is_none() } } -/// Immutable iterator over an `Option<A>` -pub struct OptionIterator<'self, A> { - priv opt: Option<&'self A> +/// An iterator that yields either one or zero elements +pub struct OptionIterator<A> { + priv opt: Option<A> } -impl<'self, A> Iterator<&'self A> for OptionIterator<'self, A> { - fn next(&mut self) -> Option<&'self A> { - util::replace(&mut self.opt, None) - } - - fn size_hint(&self) -> (uint, Option<uint>) { - match self.opt { - Some(_) => (1, Some(1)), - None => (0, Some(0)), - } - } -} - -/// Mutable iterator over an `Option<A>` -pub struct OptionMutIterator<'self, A> { - priv opt: Option<&'self mut A> -} - -impl<'self, A> Iterator<&'self mut A> for OptionMutIterator<'self, A> { - fn next(&mut self) -> Option<&'self mut A> { - util::replace(&mut self.opt, None) +impl<A> Iterator<A> for OptionIterator<A> { + #[inline] + fn next(&mut self) -> Option<A> { + self.opt.take() } + #[inline] fn size_hint(&self) -> (uint, Option<uint>) { match self.opt { Some(_) => (1, Some(1)), @@ -450,7 +436,7 @@ mod tests { use util; #[test] - fn test_unwrap_ptr() { + fn test_get_ptr() { unsafe { let x = ~0; let addr_x: *int = ::cast::transmute(&*x); @@ -462,7 +448,7 @@ mod tests { } #[test] - fn test_unwrap_str() { + fn test_get_str() { let x = ~"test"; let addr_x = x.as_imm_buf(|buf, _len| buf); let opt = Some(x); @@ -472,7 +458,7 @@ mod tests { } #[test] - fn test_unwrap_resource() { + fn test_get_resource() { struct R { i: @mut int, } @@ -530,18 +516,18 @@ mod tests { } #[test] - fn test_get_or_zero() { + fn test_unwrap_or_zero() { let some_stuff = Some(42); - assert_eq!(some_stuff.get_or_zero(), 42); + assert_eq!(some_stuff.unwrap_or_zero(), 42); let no_stuff: Option<int> = None; - assert_eq!(no_stuff.get_or_zero(), 0); + assert_eq!(no_stuff.unwrap_or_zero(), 0); } #[test] fn test_filtered() { let some_stuff = Some(42); let modified_stuff = some_stuff.filtered(|&x| {x < 10}); - assert_eq!(some_stuff.get(), 42); + assert_eq!(some_stuff.unwrap(), 42); assert!(modified_stuff.is_none()); } diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0e25d3dbe04..1f63a7c6041 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -574,7 +574,7 @@ pub fn tmpdir() -> Path { #[cfg(unix)] fn lookup() -> Path { - getenv_nonempty("TMPDIR").get_or_default(Path("/tmp")) + getenv_nonempty("TMPDIR").unwrap_or_default(Path("/tmp")) } #[cfg(windows)] @@ -582,7 +582,7 @@ pub fn tmpdir() -> Path { getenv_nonempty("TMP").or( getenv_nonempty("TEMP").or( getenv_nonempty("USERPROFILE").or( - getenv_nonempty("WINDIR")))).get_or_default(Path("C:\\Windows")) + getenv_nonempty("WINDIR")))).unwrap_or_default(Path("C:\\Windows")) } } @@ -1788,7 +1788,7 @@ mod tests { fn test_self_exe_path() { let path = os::self_exe_path(); assert!(path.is_some()); - let path = path.get(); + let path = path.unwrap(); debug!(path.clone()); // Hard to test this function diff --git a/src/libstd/ptr.rs b/src/libstd/ptr.rs index 84d55c55c2f..a9e2e4c81a9 100644 --- a/src/libstd/ptr.rs +++ b/src/libstd/ptr.rs @@ -12,6 +12,7 @@ use cast; use clone::Clone; +use iterator::{range, Iterator}; use option::{Option, Some, None}; use unstable::intrinsics; use util::swap; @@ -20,7 +21,6 @@ use util::swap; #[cfg(not(test))] use num::Int; #[cfg(not(test))] use cmp::{Eq, Ord}; -use uint; /// Calculate the offset from a pointer #[inline] @@ -240,11 +240,10 @@ pub unsafe fn array_each_with_len<T>(arr: **T, len: uint, cb: &fn(*T)) { fail!("ptr::array_each_with_len failure: arr input is null pointer"); } //let start_ptr = *arr; - uint::iterate(0, len, |e| { + for e in range(0, len) { let n = offset(arr, e as int); cb(*n); - true - }); + } debug!("array_each_with_len: after iterate"); } diff --git a/src/libstd/rand.rs b/src/libstd/rand.rs index b7d72c11ff7..4ef524d7715 100644 --- a/src/libstd/rand.rs +++ b/src/libstd/rand.rs @@ -533,7 +533,7 @@ impl<R: Rng> RngUtil for R { /// Choose an item randomly, failing if values is empty fn choose<T:Clone>(&mut self, values: &[T]) -> T { - self.choose_option(values).get() + self.choose_option(values).unwrap() } /// Choose Some(item) randomly, returning None if values is empty @@ -549,7 +549,7 @@ impl<R: Rng> RngUtil for R { * the weights is 0 */ fn choose_weighted<T:Clone>(&mut self, v: &[Weighted<T>]) -> T { - self.choose_weighted_option(v).get() + self.choose_weighted_option(v).unwrap() } /** diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 7a578465841..91f42edf0ae 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -16,27 +16,31 @@ use clone::Clone; use cmp::Eq; use either; use iterator::Iterator; -use option::{None, Option, Some}; +use option::{None, Option, Some, OptionIterator}; use vec; use vec::{OwnedVector, ImmutableVector}; use container::Container; - -/// The result type +use to_str::ToStr; +use str::StrSlice; + +/// `Result` is a type that represents either success (`Ok`) or failure (`Err`). +/// +/// In order to provide informative error messages, `E` is reqired to implement `ToStr`. +/// It is further recommended for `E` to be a descriptive error type, eg a `enum` for +/// all possible errors cases. #[deriving(Clone, Eq)] -pub enum Result<T, U> { +pub enum Result<T, E> { /// Contains the successful result value Ok(T), /// Contains the error value - Err(U) + Err(E) } -impl<T, E> Result<T, E> { - /** - * Convert to the `either` type - * - * `Ok` result variants are converted to `either::Right` variants, `Err` - * result variants are converted to `either::Left`. - */ +impl<T, E: ToStr> Result<T, E> { + /// Convert to the `either` type + /// + /// `Ok` result variants are converted to `either::Right` variants, `Err` + /// result variants are converted to `either::Left`. #[inline] pub fn to_either(self)-> either::Either<E, T>{ match self { @@ -45,18 +49,16 @@ impl<T, E> Result<T, E> { } } - /** - * Get a reference to the value out of a successful result - * - * # Failure - * - * If the result is an error - */ + /// Get a reference to the value out of a successful result + /// + /// # Failure + /// + /// If the result is an error #[inline] pub fn get_ref<'a>(&'a self) -> &'a T { match *self { Ok(ref t) => t, - Err(ref e) => fail!("get_ref called on `Err` result: %?", *e), + Err(ref e) => fail!("called `Result::get_ref()` on `Err` value: %s", e.to_str()), } } @@ -75,76 +77,90 @@ impl<T, E> Result<T, E> { !self.is_ok() } - /** - * Call a method based on a previous result - * - * If `self` is `Ok` then the value is extracted and passed to `op` - * whereupon `op`s result is returned. if `self` is `Err` then it is - * immediately returned. This function can be used to compose the results - * of two functions. - * - * Example: - * - * do read_file(file).iter |buf| { - * print_buf(buf) - * } - */ + /// Call a method based on a previous result + /// + /// If `self` is `Ok` then the value is extracted and passed to `op` + /// whereupon `op`s result is returned. if `self` is `Err` then it is + /// immediately returned. This function can be used to compose the results + /// of two functions. + /// + /// Example: + /// + /// for buf in read_file(file) { + /// print_buf(buf) + /// } #[inline] - pub fn iter(&self, f: &fn(&T)) { + pub fn iter<'r>(&'r self) -> OptionIterator<&'r T> { match *self { - Ok(ref t) => f(t), - Err(_) => (), - } + Ok(ref t) => Some(t), + Err(*) => None, + }.consume() } - /** - * Call a method based on a previous result - * - * If `self` is `Err` then the value is extracted and passed to `op` - * whereupon `op`s result is returned. if `self` is `Ok` then it is - * immediately returned. This function can be used to pass through a - * successful result while handling an error. - */ + /// Call a method based on a previous result + /// + /// If `self` is `Err` then the value is extracted and passed to `op` + /// whereupon `op`s result is returned. if `self` is `Ok` then it is + /// immediately returned. This function can be used to pass through a + /// successful result while handling an error. #[inline] - pub fn iter_err(&self, f: &fn(&E)) { + pub fn iter_err<'r>(&'r self) -> OptionIterator<&'r E> { match *self { - Ok(_) => (), - Err(ref e) => f(e), - } + Ok(*) => None, + Err(ref t) => Some(t), + }.consume() } - /// Unwraps a result, assuming it is an `Ok(T)` + /// Unwraps a result, yielding the content of an `Ok`. + /// Fails if the value is a `Err` with an error message derived + /// from `E`'s `ToStr` implementation. #[inline] pub fn unwrap(self) -> T { match self { Ok(t) => t, - Err(_) => fail!("unwrap called on an `Err` result"), + Err(e) => fail!("called `Result::unwrap()` on `Err` value: %s", e.to_str()), } } - /// Unwraps a result, assuming it is an `Err(U)` + /// Unwraps a result, yielding the content of an `Err`. + /// Fails if the value is a `Ok`. #[inline] pub fn unwrap_err(self) -> E { + self.expect_err("called `Result::unwrap_err()` on `Ok` value") + } + + /// Unwraps a result, yielding the content of an `Ok`. + /// Fails if the value is a `Err` with a custom failure message. + #[inline] + pub fn expect(self, reason: &str) -> T { + match self { + Ok(t) => t, + Err(_) => fail!(reason.to_owned()), + } + } + + /// Unwraps a result, yielding the content of an `Err` + /// Fails if the value is a `Ok` with a custom failure message. + #[inline] + pub fn expect_err(self, reason: &str) -> E { match self { Err(e) => e, - Ok(_) => fail!("unwrap called on an `Ok` result"), + Ok(_) => fail!(reason.to_owned()), } } - /** - * Call a method based on a previous result - * - * If `self` is `Ok` then the value is extracted and passed to `op` - * whereupon `op`s result is returned. if `self` is `Err` then it is - * immediately returned. This function can be used to compose the results - * of two functions. - * - * Example: - * - * let res = do read_file(file) |buf| { - * Ok(parse_bytes(buf)) - * }; - */ + /// Call a method based on a previous result + /// + /// If `self` is `Ok` then the value is extracted and passed to `op` + /// whereupon `op`s result is returned. if `self` is `Err` then it is + /// immediately returned. This function can be used to compose the results + /// of two functions. + /// + /// Example: + /// + /// let res = do read_file(file) |buf| { + /// Ok(parse_bytes(buf)) + /// }; #[inline] pub fn chain<U>(self, op: &fn(T) -> Result<U, E>) -> Result<U, E> { match self { @@ -153,14 +169,12 @@ impl<T, E> Result<T, E> { } } - /** - * Call a function based on a previous result - * - * If `self` is `Err` then the value is extracted and passed to `op` - * whereupon `op`s result is returned. if `self` is `Ok` then it is - * immediately returned. This function can be used to pass through a - * successful result while handling an error. - */ + /// Call a function based on a previous result + /// + /// If `self` is `Err` then the value is extracted and passed to `op` + /// whereupon `op`s result is returned. if `self` is `Ok` then it is + /// immediately returned. This function can be used to pass through a + /// successful result while handling an error. #[inline] pub fn chain_err<F>(self, op: &fn(E) -> Result<T, F>) -> Result<T, F> { match self { @@ -170,32 +184,15 @@ impl<T, E> Result<T, E> { } } -impl<T: Clone, E> Result<T, E> { - /** - * Get the value out of a successful result - * - * # Failure - * - * If the result is an error - */ - #[inline] - pub fn get(&self) -> T { - match *self { - Ok(ref t) => t.clone(), - Err(ref e) => fail!("get called on `Err` result: %?", *e), - } - } - - /** - * Call a method based on a previous result - * - * If `self` is `Err` then the value is extracted and passed to `op` - * whereupon `op`s result is wrapped in an `Err` and returned. if `self` is - * `Ok` then it is immediately returned. This function can be used to pass - * through a successful result while handling an error. - */ +impl<T: Clone, E: ToStr> Result<T, E> { + /// Call a method based on a previous result + /// + /// If `self` is `Err` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in an `Err` and returned. if `self` is + /// `Ok` then it is immediately returned. This function can be used to pass + /// through a successful result while handling an error. #[inline] - pub fn map_err<F:Clone>(&self, op: &fn(&E) -> F) -> Result<T,F> { + pub fn map_err<F: Clone>(&self, op: &fn(&E) -> F) -> Result<T,F> { match *self { Ok(ref t) => Ok(t.clone()), Err(ref e) => Err(op(e)) @@ -203,62 +200,57 @@ impl<T: Clone, E> Result<T, E> { } } -impl<T, E: Clone> Result<T, E> { - /** - * Get the value out of an error result - * - * # Failure - * - * If the result is not an error - */ +impl<T, E: Clone + ToStr> Result<T, E> { + /// Call a method based on a previous result + /// + /// If `self` is `Ok` then the value is extracted and passed to `op` + /// whereupon `op`s result is wrapped in `Ok` and returned. if `self` is + /// `Err` then it is immediately returned. This function can be used to + /// compose the results of two functions. + /// + /// Example: + /// + /// let res = do read_file(file).map |buf| { + /// parse_bytes(buf) + /// }; #[inline] - pub fn get_err(&self) -> E { + pub fn map<U>(&self, op: &fn(&T) -> U) -> Result<U,E> { match *self { - Err(ref e) => e.clone(), - Ok(_) => fail!("get_err called on `Ok` result") + Ok(ref t) => Ok(op(t)), + Err(ref e) => Err(e.clone()) } } +} - /** - * Call a method based on a previous result - * - * If `self` is `Ok` then the value is extracted and passed to `op` - * whereupon `op`s result is wrapped in `Ok` and returned. if `self` is - * `Err` then it is immediately returned. This function can be used to - * compose the results of two functions. - * - * Example: - * - * let res = do read_file(file).map |buf| { - * parse_bytes(buf) - * }; - */ - #[inline] - pub fn map<U:Clone>(&self, op: &fn(&T) -> U) -> Result<U,E> { - match *self { - Ok(ref t) => Ok(op(t)), - Err(ref e) => Err(e.clone()) +#[inline] +#[allow(missing_doc)] +pub fn map_opt<T, U: ToStr, V>(o_t: &Option<T>, + op: &fn(&T) -> Result<V,U>) -> Result<Option<V>,U> { + match *o_t { + None => Ok(None), + Some(ref t) => match op(t) { + Ok(v) => Ok(Some(v)), + Err(e) => Err(e) } } } -/** - * Maps each element in the vector `ts` using the operation `op`. Should an - * error occur, no further mappings are performed and the error is returned. - * Should no error occur, a vector containing the result of each map is - * returned. - * - * Here is an example which increments every integer in a vector, - * checking for overflow: - * - * fn inc_conditionally(x: uint) -> result<uint,str> { - * if x == uint::max_value { return Err("overflow"); } - * else { return Ok(x+1u); } - * } - * map(~[1u, 2u, 3u], inc_conditionally).chain {|incd| - * assert!(incd == ~[2u, 3u, 4u]); - * } - */ +// FIXME: #8228 Replaceable by an external iterator? +/// Maps each element in the vector `ts` using the operation `op`. Should an +/// error occur, no further mappings are performed and the error is returned. +/// Should no error occur, a vector containing the result of each map is +/// returned. +/// +/// Here is an example which increments every integer in a vector, +/// checking for overflow: +/// +/// fn inc_conditionally(x: uint) -> result<uint,str> { +/// if x == uint::max_value { return Err("overflow"); } +/// else { return Ok(x+1u); } +/// } +/// map(~[1u, 2u, 3u], inc_conditionally).chain {|incd| +/// assert!(incd == ~[2u, 3u, 4u]); +/// } #[inline] pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>) -> Result<~[V],U> { @@ -272,36 +264,17 @@ pub fn map_vec<T,U,V>(ts: &[T], op: &fn(&T) -> Result<V,U>) return Ok(vs); } +// FIXME: #8228 Replaceable by an external iterator? +/// Same as map, but it operates over two parallel vectors. +/// +/// A precondition is used here to ensure that the vectors are the same +/// length. While we do not often use preconditions in the standard +/// library, a precondition is used here because result::t is generally +/// used in 'careful' code contexts where it is both appropriate and easy +/// to accommodate an error like the vectors being of different lengths. #[inline] -#[allow(missing_doc)] -pub fn map_opt<T, - U, - V>( - o_t: &Option<T>, - op: &fn(&T) -> Result<V,U>) - -> Result<Option<V>,U> { - match *o_t { - None => Ok(None), - Some(ref t) => match op(t) { - Ok(v) => Ok(Some(v)), - Err(e) => Err(e) - } - } -} - -/** - * Same as map, but it operates over two parallel vectors. - * - * A precondition is used here to ensure that the vectors are the same - * length. While we do not often use preconditions in the standard - * library, a precondition is used here because result::t is generally - * used in 'careful' code contexts where it is both appropriate and easy - * to accommodate an error like the vectors being of different lengths. - */ -#[inline] -pub fn map_vec2<S,T,U,V>(ss: &[S], ts: &[T], - op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> { - +pub fn map_vec2<S, T, U: ToStr, V>(ss: &[S], ts: &[T], + op: &fn(&S,&T) -> Result<V,U>) -> Result<~[V],U> { assert!(vec::same_length(ss, ts)); let n = ts.len(); let mut vs = vec::with_capacity(n); @@ -316,15 +289,13 @@ pub fn map_vec2<S,T,U,V>(ss: &[S], ts: &[T], return Ok(vs); } -/** - * Applies op to the pairwise elements from `ss` and `ts`, aborting on - * error. This could be implemented using `map_zip()` but it is more efficient - * on its own as no result vector is built. - */ +// FIXME: #8228 Replaceable by an external iterator? +/// Applies op to the pairwise elements from `ss` and `ts`, aborting on +/// error. This could be implemented using `map_zip()` but it is more efficient +/// on its own as no result vector is built. #[inline] -pub fn iter_vec2<S,T,U>(ss: &[S], ts: &[T], - op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> { - +pub fn iter_vec2<S, T, U: ToStr>(ss: &[S], ts: &[T], + op: &fn(&S,&T) -> Result<(),U>) -> Result<(),U> { assert!(vec::same_length(ss, ts)); let n = ts.len(); let mut i = 0u; @@ -353,32 +324,36 @@ mod tests { #[test] pub fn chain_success() { - assert_eq!(op1().chain(op2).get(), 667u); + assert_eq!(op1().chain(op2).unwrap(), 667u); } #[test] pub fn chain_failure() { - assert_eq!(op3().chain( op2).get_err(), ~"sadface"); + assert_eq!(op3().chain( op2).unwrap_err(), ~"sadface"); } #[test] pub fn test_impl_iter() { let mut valid = false; - Ok::<~str, ~str>(~"a").iter(|_x| valid = true); + let okval = Ok::<~str, ~str>(~"a"); + do okval.iter().next().map |_| { valid = true; }; assert!(valid); - Err::<~str, ~str>(~"b").iter(|_x| valid = false); + let errval = Err::<~str, ~str>(~"b"); + do errval.iter().next().map |_| { valid = false; }; assert!(valid); } #[test] pub fn test_impl_iter_err() { let mut valid = true; - Ok::<~str, ~str>(~"a").iter_err(|_x| valid = false); + let okval = Ok::<~str, ~str>(~"a"); + do okval.iter_err().next().map |_| { valid = false }; assert!(valid); valid = false; - Err::<~str, ~str>(~"b").iter_err(|_x| valid = true); + let errval = Err::<~str, ~str>(~"b"); + do errval.iter_err().next().map |_| { valid = true }; assert!(valid); } diff --git a/src/libstd/rt/io/flate.rs b/src/libstd/rt/io/flate.rs index e57b80658ee..16bca850fd2 100644 --- a/src/libstd/rt/io/flate.rs +++ b/src/libstd/rt/io/flate.rs @@ -10,7 +10,7 @@ //! Some various other I/O types -// NOTE: These ultimately belong somewhere else +// FIXME(#3660): should move to libextra use prelude::*; use super::*; @@ -115,7 +115,7 @@ mod test { let mem_reader = MemReader::new(buf); let mut inflate_reader = InflateReader::new(mem_reader); let mut out_bytes = [0, .. 100]; - let bytes_read = inflate_reader.read(out_bytes).get(); + let bytes_read = inflate_reader.read(out_bytes).unwrap(); assert_eq!(bytes_read, in_bytes.len()); let out_msg = str::from_bytes(out_bytes); assert!(in_msg == out_msg); diff --git a/src/libstd/rt/io/mod.rs b/src/libstd/rt/io/mod.rs index 838c2d86c9f..c980dc9d73e 100644 --- a/src/libstd/rt/io/mod.rs +++ b/src/libstd/rt/io/mod.rs @@ -243,6 +243,8 @@ Out of scope */ use prelude::*; +use to_str::ToStr; +use str::{StrSlice, OwnedStr}; // Reexports pub use self::stdio::stdin; @@ -334,6 +336,20 @@ pub struct IoError { detail: Option<~str> } +// FIXME: #8242 implementing manually because deriving doesn't work for some reason +impl ToStr for IoError { + fn to_str(&self) -> ~str { + let mut s = ~"IoError { kind: "; + s.push_str(self.kind.to_str()); + s.push_str(", desc: "); + s.push_str(self.desc); + s.push_str(", detail: "); + s.push_str(self.detail.to_str()); + s.push_str(" }"); + s + } +} + #[deriving(Eq)] pub enum IoErrorKind { PreviousIoError, @@ -348,6 +364,24 @@ pub enum IoErrorKind { BrokenPipe } +// FIXME: #8242 implementing manually because deriving doesn't work for some reason +impl ToStr for IoErrorKind { + fn to_str(&self) -> ~str { + match *self { + PreviousIoError => ~"PreviousIoError", + OtherIoError => ~"OtherIoError", + EndOfFile => ~"EndOfFile", + FileNotFound => ~"FileNotFound", + PermissionDenied => ~"PermissionDenied", + ConnectionFailed => ~"ConnectionFailed", + Closed => ~"Closed", + ConnectionRefused => ~"ConnectionRefused", + ConnectionReset => ~"ConnectionReset", + BrokenPipe => ~"BrokenPipe" + } + } +} + // XXX: Can't put doc comments on macros // Raised by `I/O` operations on error. condition! { @@ -505,4 +539,4 @@ pub fn placeholder_error() -> IoError { desc: "Placeholder error. You shouldn't be seeing this", detail: None } -} \ No newline at end of file +} diff --git a/src/libstd/rt/kill.rs b/src/libstd/rt/kill.rs index deec8dd37a6..3372c13b877 100644 --- a/src/libstd/rt/kill.rs +++ b/src/libstd/rt/kill.rs @@ -193,6 +193,10 @@ impl BlockedTask { /// Create a blocked task, unless the task was already killed. pub fn try_block(mut task: ~Task) -> Either<~Task, BlockedTask> { + // NB: As an optimization, we could give a free pass to being unkillable + // to tasks whose taskgroups haven't been initialized yet, but that + // introduces complications with select() and with the test cases below, + // and it's not clear the uncommon performance boost is worth it. if task.death.unkillable > 0 { Right(Unkillable(task)) } else { @@ -205,11 +209,10 @@ impl BlockedTask { let flag_arc = match task.death.spare_kill_flag.take() { Some(spare_flag) => spare_flag, None => { - // FIXME(#7544): Uncomment this when terminate_current_task - // stops being *terrible*. That's the only place that violates - // the assumption of "becoming unkillable will fail if the - // task was killed". - // rtassert!(task.unwinder.unwinding); + // A task that kills us won't have a spare kill flag to + // give back to us, so we restore it ourselves here. This + // situation should only arise when we're already failing. + rtassert!(task.unwinder.unwinding); (*task.death.kill_handle.get_ref().get()).killed.clone() } }; diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index 33e83fd9040..760ca8a9ada 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -365,7 +365,7 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int { rtdebug!("about to create the main scheduler task"); - let mut main_sched = main_sched.get(); + let mut main_sched = main_sched.unwrap(); let home = Sched(main_sched.make_handle()); let mut main_task = ~Task::new_root_homed(&mut main_sched.stack_pool, diff --git a/src/libstd/rt/task.rs b/src/libstd/rt/task.rs index cb949edd7bb..4c5e4bdc3c1 100644 --- a/src/libstd/rt/task.rs +++ b/src/libstd/rt/task.rs @@ -465,10 +465,10 @@ mod test { do run_in_newsched_task() { static key: local_data::Key<@~str> = &local_data::Key; local_data::set(key, @~"data"); - assert!(*local_data::get(key, |k| k.map(|&k| *k)).get() == ~"data"); + assert!(*local_data::get(key, |k| k.map(|&k| *k)).unwrap() == ~"data"); static key2: local_data::Key<@~str> = &local_data::Key; local_data::set(key2, @~"data"); - assert!(*local_data::get(key2, |k| k.map(|&k| *k)).get() == ~"data"); + assert!(*local_data::get(key2, |k| k.map(|&k| *k)).unwrap() == ~"data"); } } diff --git a/src/libstd/rt/test.rs b/src/libstd/rt/test.rs index 2427da01a0c..8b5215ae969 100644 --- a/src/libstd/rt/test.rs +++ b/src/libstd/rt/test.rs @@ -154,7 +154,7 @@ pub fn run_in_mt_newsched_task(f: ~fn()) { do run_in_bare_thread { let nthreads = match os::getenv("RUST_RT_TEST_THREADS") { - Some(nstr) => FromStr::from_str(nstr).get(), + Some(nstr) => FromStr::from_str(nstr).unwrap(), None => { // Using more threads than cores in test code // to force the OS to preempt them frequently. @@ -362,7 +362,7 @@ pub fn stress_factor() -> uint { use os::getenv; match getenv("RUST_RT_STRESS") { - Some(val) => uint::from_str(val).get(), + Some(val) => uint::from_str(val).unwrap(), None => 1 } } diff --git a/src/libstd/rt/util.rs b/src/libstd/rt/util.rs index a1169954688..40e5c8d4bf1 100644 --- a/src/libstd/rt/util.rs +++ b/src/libstd/rt/util.rs @@ -31,7 +31,7 @@ pub fn num_cpus() -> uint { /// either `RUST_THREADS` or `num_cpus`. pub fn default_sched_threads() -> uint { match os::getenv("RUST_THREADS") { - Some(nstr) => FromStr::from_str(nstr).get(), + Some(nstr) => FromStr::from_str(nstr).unwrap(), None => num_cpus() } } @@ -118,4 +118,4 @@ pub fn get_exit_status() -> int { extern { fn rust_get_exit_status_newrt() -> libc::uintptr_t; } -} \ No newline at end of file +} diff --git a/src/libstd/rt/uv/net.rs b/src/libstd/rt/uv/net.rs index 67d3bbef8a9..fd3042899f6 100644 --- a/src/libstd/rt/uv/net.rs +++ b/src/libstd/rt/uv/net.rs @@ -108,7 +108,7 @@ fn uv_socket_addr_as_socket_addr<T>(addr: UvSocketAddr, f: &fn(SocketAddr) -> T) "" => ~[], // IPv4-Mapped/Compatible IPv6 Address? s if s.find('.').is_some() => { - let i = s.rfind(':').get_or_default(-1); + let i = s.rfind(':').unwrap_or_default(-1); let b = s.slice(i + 1, s.len()); // the ipv4 part @@ -614,7 +614,7 @@ mod test { do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); - assert_eq!(status.get().name(), ~"ECONNREFUSED"); + assert_eq!(status.unwrap().name(), ~"ECONNREFUSED"); stream_watcher.close(||()); } loop_.run(); @@ -632,7 +632,7 @@ mod test { do tcp_watcher.connect(addr) |stream_watcher, status| { rtdebug!("tcp_watcher.connect!"); assert!(status.is_some()); - assert_eq!(status.get().name(), ~"ECONNREFUSED"); + assert_eq!(status.unwrap().name(), ~"ECONNREFUSED"); stream_watcher.close(||()); } loop_.run(); diff --git a/src/libstd/rt/uv/uvio.rs b/src/libstd/rt/uv/uvio.rs index 01d01de54ef..038ebad3540 100644 --- a/src/libstd/rt/uv/uvio.rs +++ b/src/libstd/rt/uv/uvio.rs @@ -278,7 +278,7 @@ impl IoFactory for UvIoFactory { rtdebug!("status is some"); let task_cell = Cell::new(task_cell.take()); do stream_watcher.close { - let res = Err(uv_error_to_io_error(status.get())); + let res = Err(uv_error_to_io_error(status.unwrap())); unsafe { (*result_cell_ptr).put_back(res); } let scheduler = Local::take::<Scheduler>(); scheduler.resume_blocked_task_immediately(task_cell.take()); diff --git a/src/libstd/str.rs b/src/libstd/str.rs index 60148e1432c..7c3a3ca8619 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -59,7 +59,7 @@ pub fn from_bytes(vv: &[u8]) -> ~str { use str::not_utf8::cond; if !is_utf8(vv) { - let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).get(); + let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).unwrap(); cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", first_bad_byte as uint)) } else { @@ -76,7 +76,7 @@ pub fn from_bytes_owned(vv: ~[u8]) -> ~str { use str::not_utf8::cond; if !is_utf8(vv) { - let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).get(); + let first_bad_byte = *vv.iter().find_(|&b| !is_utf8([*b])).unwrap(); cond.raise(fmt!("from_bytes: input is not UTF-8; first bad byte is %u", first_bad_byte as uint)) } else { @@ -1029,7 +1029,7 @@ pub mod raw { /// If end is greater than the length of the string. #[cfg(stage0)] #[inline] - pub unsafe fn slice_bytes(s: &str, begin: uint, end: uint) -> &str { + pub unsafe fn slice_bytes<'a>(s: &'a str, begin: uint, end: uint) -> &'a str { do s.as_imm_buf |sbuf, n| { assert!((begin <= end)); assert!((end <= n)); diff --git a/src/libstd/task/mod.rs b/src/libstd/task/mod.rs index f7a943f8d2f..225a4b8cfd2 100644 --- a/src/libstd/task/mod.rs +++ b/src/libstd/task/mod.rs @@ -926,7 +926,7 @@ fn test_named_task() { t.name(~"ada lovelace"); do t.spawn { do with_task_name |name| { - assert!(name.get() == "ada lovelace"); + assert!(name.unwrap() == "ada lovelace"); } } } diff --git a/src/libstd/task/spawn.rs b/src/libstd/task/spawn.rs index 3bf2f255f57..527b20b0e90 100644 --- a/src/libstd/task/spawn.rs +++ b/src/libstd/task/spawn.rs @@ -568,7 +568,8 @@ impl RuntimeGlue { let me = Local::unsafe_borrow::<Task>(); blk(match (*me).taskgroup { None => { - // Main task, doing first spawn ever. Lazily initialize. + // First task in its (unlinked/unsupervised) taskgroup. + // Lazily initialize. let mut members = TaskSet::new(); let my_handle = (*me).death.kill_handle.get_ref().clone(); members.insert(NewTask(my_handle)); @@ -591,37 +592,46 @@ impl RuntimeGlue { } } +// Returns 'None' in the case where the child's TG should be lazily initialized. fn gen_child_taskgroup(linked: bool, supervised: bool) - -> (TaskGroupArc, AncestorList, bool) { - do RuntimeGlue::with_my_taskgroup |spawner_group| { - let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone())); - if linked { - // Child is in the same group as spawner. - // Child's ancestors are spawner's ancestors. - // Propagate main-ness. - (spawner_group.tasks.clone(), ancestors, spawner_group.is_main) - } else { - // Child is in a separate group from spawner. - let g = Exclusive::new(Some(TaskGroupData { - members: TaskSet::new(), - descendants: TaskSet::new(), - })); - let a = if supervised { - let new_generation = incr_generation(&ancestors); - assert!(new_generation < uint::max_value); - // Child's ancestors start with the spawner. - // Build a new node in the ancestor list. - AncestorList(Some(Exclusive::new(AncestorNode { - generation: new_generation, - parent_group: spawner_group.tasks.clone(), - ancestors: ancestors, - }))) + -> Option<(TaskGroupArc, AncestorList, bool)> { + // FIXME(#7544): Not safe to lazily initialize in the old runtime. Remove + // this context check once 'spawn_raw_oldsched' is gone. + if context() == OldTaskContext || linked || supervised { + // with_my_taskgroup will lazily initialize the parent's taskgroup if + // it doesn't yet exist. We don't want to call it in the unlinked case. + do RuntimeGlue::with_my_taskgroup |spawner_group| { + let ancestors = AncestorList(spawner_group.ancestors.map(|x| x.clone())); + if linked { + // Child is in the same group as spawner. + // Child's ancestors are spawner's ancestors. + // Propagate main-ness. + Some((spawner_group.tasks.clone(), ancestors, spawner_group.is_main)) } else { - // Child has no ancestors. - AncestorList(None) - }; - (g, a, false) + // Child is in a separate group from spawner. + let g = Exclusive::new(Some(TaskGroupData { + members: TaskSet::new(), + descendants: TaskSet::new(), + })); + let a = if supervised { + let new_generation = incr_generation(&ancestors); + assert!(new_generation < uint::max_value); + // Child's ancestors start with the spawner. + // Build a new node in the ancestor list. + AncestorList(Some(Exclusive::new(AncestorNode { + generation: new_generation, + parent_group: spawner_group.tasks.clone(), + ancestors: ancestors, + }))) + } else { + // Child has no ancestors. + AncestorList(None) + }; + Some((g, a, false)) + } } + } else { + None } } @@ -670,20 +680,24 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let child_wrapper: ~fn() = || { // Child task runs this code. - let child_data = Cell::new(child_data.take()); // :( - let enlist_success = do Local::borrow::<Task, bool> |me| { - let (child_tg, ancestors, is_main) = child_data.take(); - let mut ancestors = ancestors; - // FIXME(#7544): Optimize out the xadd in this clone, somehow. - let handle = me.death.kill_handle.get_ref().clone(); - // Atomically try to get into all of our taskgroups. - if enlist_many(NewTask(handle), &child_tg, &mut ancestors) { - // Got in. We can run the provided child body, and can also run - // the taskgroup's exit-time-destructor afterward. - me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None)); - true - } else { - false + + // If child data is 'None', the enlist is vacuously successful. + let enlist_success = do child_data.take().map_consume_default(true) |child_data| { + let child_data = Cell::new(child_data); // :( + do Local::borrow::<Task, bool> |me| { + let (child_tg, ancestors, is_main) = child_data.take(); + let mut ancestors = ancestors; + // FIXME(#7544): Optimize out the xadd in this clone, somehow. + let handle = me.death.kill_handle.get_ref().clone(); + // Atomically try to get into all of our taskgroups. + if enlist_many(NewTask(handle), &child_tg, &mut ancestors) { + // Got in. We can run the provided child body, and can also run + // the taskgroup's exit-time-destructor afterward. + me.taskgroup = Some(Taskgroup(child_tg, ancestors, is_main, None)); + true + } else { + false + } } }; // Should be run after the local-borrowed task is returned. @@ -749,7 +763,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { let join_task = join_task_cell.take(); let bootstrap_task = ~do Task::new_root(&mut new_sched.stack_pool) || { - rtdebug!("boostraping a 1:1 scheduler"); + rtdebug!("bootstrapping a 1:1 scheduler"); }; new_sched.bootstrap(bootstrap_task); @@ -793,7 +807,7 @@ fn spawn_raw_newsched(mut opts: TaskOpts, f: ~fn()) { fn spawn_raw_oldsched(mut opts: TaskOpts, f: ~fn()) { let (child_tg, ancestors, is_main) = - gen_child_taskgroup(opts.linked, opts.supervised); + gen_child_taskgroup(opts.linked, opts.supervised).expect("old runtime needs TG"); unsafe { let child_data = Cell::new((child_tg, ancestors, f)); diff --git a/src/libstd/trie.rs b/src/libstd/trie.rs index 679d36b87f1..6f61d29780f 100644 --- a/src/libstd/trie.rs +++ b/src/libstd/trie.rs @@ -14,6 +14,7 @@ use prelude::*; use iterator::{IteratorUtil, FromIterator, Extendable}; use uint; use util::{swap, replace}; +use vec; // FIXME: #5244: need to manually update the TrieNode constructor static SHIFT: uint = 4; @@ -146,6 +147,15 @@ impl<T> TrieMap<T> { pub fn each_value_reverse(&self, f: &fn(&T) -> bool) -> bool { self.each_reverse(|_, v| f(v)) } + + /// Get an iterator over the key-value pairs in the map + pub fn iter<'a>(&'a self) -> TrieMapIterator<'a, T> { + TrieMapIterator { + stack: ~[self.root.children.iter()], + remaining_min: self.length, + remaining_max: self.length + } + } } impl<T, Iter: Iterator<(uint, T)>> FromIterator<(uint, T), Iter> for TrieMap<T> { @@ -217,6 +227,12 @@ impl TrieSet { pub fn each_reverse(&self, f: &fn(&uint) -> bool) -> bool { self.map.each_key_reverse(f) } + + /// Get an iterator over the values in the set + #[inline] + pub fn iter<'a>(&'a self) -> TrieSetIterator<'a> { + TrieSetIterator{iter: self.map.iter()} + } } impl<Iter: Iterator<uint>> FromIterator<uint, Iter> for TrieSet { @@ -366,6 +382,61 @@ fn remove<T>(count: &mut uint, child: &mut Child<T>, key: uint, return ret; } +/// Forward iterator over a map +pub struct TrieMapIterator<'self, T> { + priv stack: ~[vec::VecIterator<'self, Child<T>>], + priv remaining_min: uint, + priv remaining_max: uint +} + +impl<'self, T> Iterator<(uint, &'self T)> for TrieMapIterator<'self, T> { + fn next(&mut self) -> Option<(uint, &'self T)> { + while !self.stack.is_empty() { + match self.stack[self.stack.len() - 1].next() { + None => { + self.stack.pop(); + } + Some(ref child) => { + match **child { + Internal(ref node) => { + self.stack.push(node.children.iter()); + } + External(key, ref value) => { + self.remaining_max -= 1; + if self.remaining_min > 0 { + self.remaining_min -= 1; + } + return Some((key, value)); + } + Nothing => {} + } + } + } + } + return None; + } + + #[inline] + fn size_hint(&self) -> (uint, Option<uint>) { + (self.remaining_min, Some(self.remaining_max)) + } +} + +/// Forward iterator over a set +pub struct TrieSetIterator<'self> { + priv iter: TrieMapIterator<'self, ()> +} + +impl<'self> Iterator<uint> for TrieSetIterator<'self> { + fn next(&mut self) -> Option<uint> { + do self.iter.next().map |&(key, _)| { key } + } + + fn size_hint(&self) -> (uint, Option<uint>) { + self.iter.size_hint() + } +} + #[cfg(test)] pub fn check_integrity<T>(trie: &TrieNode<T>) { assert!(trie.count != 0); @@ -553,6 +624,29 @@ mod test_map { assert_eq!(map.find(&k), Some(&v)); } } + + #[test] + fn test_iteration() { + let empty_map : TrieMap<uint> = TrieMap::new(); + assert_eq!(empty_map.iter().next(), None); + + let first = uint::max_value - 10000; + let last = uint::max_value; + + let mut map = TrieMap::new(); + do uint::range_rev(last, first) |x| { + map.insert(x, x / 2); + true + }; + + let mut i = 0; + for (k, &v) in map.iter() { + assert_eq!(k, first + i); + assert_eq!(v, k / 2); + i += 1; + } + assert_eq!(i, last - first); + } } #[cfg(test)] diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index f037aa2b7e7..0259b547ab3 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -195,10 +195,8 @@ pub fn build<A>(builder: &fn(push: &fn(v: A))) -> ~[A] { * onto the vector being constructed. */ #[inline] -pub fn build_sized_opt<A>(size: Option<uint>, - builder: &fn(push: &fn(v: A))) - -> ~[A] { - build_sized(size.get_or_default(4), builder) +pub fn build_sized_opt<A>(size: Option<uint>, builder: &fn(push: &fn(v: A))) -> ~[A] { + build_sized(size.unwrap_or_default(4), builder) } /// An iterator over the slices of a vector separated by elements that @@ -481,6 +479,7 @@ pub fn each_permutation<T:Clone>(values: &[T], fun: &fn(perm : &[T]) -> bool) -> /// An iterator over the (overlapping) slices of length `size` within /// a vector. +#[deriving(Clone)] pub struct WindowIter<'self, T> { priv v: &'self [T], priv size: uint @@ -500,6 +499,10 @@ impl<'self, T> Iterator<&'self [T]> for WindowIter<'self, T> { /// An iterator over a vector in (non-overlapping) chunks (`size` /// elements at a time). +/// +/// When the vector len is not evenly divided by the chunk size, +/// the last slice of the iteration will be the remainer. +#[deriving(Clone)] pub struct ChunkIter<'self, T> { priv v: &'self [T], priv size: uint @@ -507,16 +510,49 @@ pub struct ChunkIter<'self, T> { impl<'self, T> Iterator<&'self [T]> for ChunkIter<'self, T> { fn next(&mut self) -> Option<&'self [T]> { - if self.size == 0 { + if self.v.len() == 0 { None - } else if self.size >= self.v.len() { - // finished - self.size = 0; - Some(self.v) } else { - let ret = Some(self.v.slice(0, self.size)); - self.v = self.v.slice(self.size, self.v.len()); - ret + let chunksz = cmp::min(self.v.len(), self.size); + let (fst, snd) = (self.v.slice_to(chunksz), + self.v.slice_from(chunksz)); + self.v = snd; + Some(fst) + } + } +} + +impl<'self, T> DoubleEndedIterator<&'self [T]> for ChunkIter<'self, T> { + fn next_back(&mut self) -> Option<&'self [T]> { + if self.v.len() == 0 { + None + } else { + let remainder = self.v.len() % self.size; + let chunksz = if remainder != 0 { remainder } else { self.size }; + let (fst, snd) = (self.v.slice_to(self.v.len() - chunksz), + self.v.slice_from(self.v.len() - chunksz)); + self.v = fst; + Some(snd) + } + } +} + +impl<'self, T> RandomAccessIterator<&'self [T]> for ChunkIter<'self, T> { + #[inline] + fn indexable(&self) -> uint { + self.v.len()/self.size + if self.v.len() % self.size != 0 { 1 } else { 0 } + } + + #[inline] + fn idx(&self, index: uint) -> Option<&'self [T]> { + if index < self.indexable() { + let lo = index * self.size; + let mut hi = lo + self.size; + if hi < lo || hi > self.v.len() { hi = self.v.len(); } + + Some(self.v.slice(lo, hi)) + } else { + None } } } @@ -3380,6 +3416,14 @@ mod tests { assert_eq!(v.chunk_iter(2).collect::<~[&[int]]>(), ~[&[1i,2], &[3,4], &[5]]); assert_eq!(v.chunk_iter(3).collect::<~[&[int]]>(), ~[&[1i,2,3], &[4,5]]); assert_eq!(v.chunk_iter(6).collect::<~[&[int]]>(), ~[&[1i,2,3,4,5]]); + + assert_eq!(v.chunk_iter(2).invert().collect::<~[&[int]]>(), ~[&[5i], &[3,4], &[1,2]]); + let it = v.chunk_iter(2); + assert_eq!(it.indexable(), 3); + assert_eq!(it.idx(0).unwrap(), &[1,2]); + assert_eq!(it.idx(1).unwrap(), &[3,4]); + assert_eq!(it.idx(2).unwrap(), &[5]); + assert_eq!(it.idx(3), None); } #[test] |
