diff --git a/src/librustc/metadata/creader.rs b/src/librustc/metadata/creader.rs index eaf01241c8165..c8c4a396c87af 100644 --- a/src/librustc/metadata/creader.rs +++ b/src/librustc/metadata/creader.rs @@ -57,6 +57,7 @@ pub fn read_crates(diag: @mut span_handler, warn_if_multiple_versions(e, diag, *e.crate_cache); } +#[deriving(Clone)] struct cache_entry { cnum: int, span: span, @@ -76,22 +77,13 @@ fn dump_crates(crate_cache: &[cache_entry]) { fn warn_if_multiple_versions(e: @mut Env, diag: @mut span_handler, crate_cache: &[cache_entry]) { - use std::either::*; - if crate_cache.len() != 0u { let name = loader::crate_name_from_metas( *crate_cache[crate_cache.len() - 1].metas ); - let vec: ~[Either] = crate_cache.iter().map(|&entry| { - let othername = loader::crate_name_from_metas(*entry.metas); - if name == othername { - Left(entry) - } else { - Right(entry) - } - }).collect(); - let (matches, non_matches) = partition(vec); + let (matches, non_matches) = crate_cache.partitioned(|entry| + name == loader::crate_name_from_metas(*entry.metas)); assert!(!matches.is_empty()); diff --git a/src/librustc/middle/typeck/infer/combine.rs b/src/librustc/middle/typeck/infer/combine.rs index b1492cac16e73..161d96d828b47 100644 --- a/src/librustc/middle/typeck/infer/combine.rs +++ b/src/librustc/middle/typeck/infer/combine.rs @@ -68,7 +68,7 @@ use middle::typeck::infer::{InferCtxt, cres, ures}; use middle::typeck::infer::{TypeTrace}; use util::common::indent; -use std::result::{iter_vec2, map_vec2}; +use std::result; use std::vec; use syntax::ast::{Onceness, purity}; use syntax::ast; @@ -275,9 +275,9 @@ pub fn super_tps( // variance. if vec::same_length(as_, bs) { - iter_vec2(as_, bs, |a, b| { - eq_tys(this, *a, *b) - }).then(|| Ok(as_.to_owned()) ) + result::fold_(as_.iter().zip(bs.iter()) + .map(|(a, b)| eq_tys(this, *a, *b))) + .then(|| Ok(as_.to_owned())) } else { Err(ty::terr_ty_param_size( expected_found(this, as_.len(), bs.len()))) @@ -427,7 +427,8 @@ pub fn super_fn_sigs( { fn argvecs(this: &C, a_args: &[ty::t], b_args: &[ty::t]) -> cres<~[ty::t]> { if vec::same_length(a_args, b_args) { - map_vec2(a_args, b_args, |a, b| this.args(*a, *b)) + result::collect(a_args.iter().zip(b_args.iter()) + .map(|(a, b)| this.args(*a, *b))) } else { Err(ty::terr_arg_count) } @@ -586,8 +587,9 @@ pub fn super_tys( (&ty::ty_tup(ref as_), &ty::ty_tup(ref bs)) => { if as_.len() == bs.len() { - map_vec2(*as_, *bs, |a, b| this.tys(*a, *b) ) - .chain(|ts| Ok(ty::mk_tup(tcx, ts)) ) + result::collect(as_.iter().zip(bs.iter()) + .map(|(a, b)| this.tys(*a, *b))) + .chain(|ts| Ok(ty::mk_tup(tcx, ts)) ) } else { Err(ty::terr_tuple_size( expected_found(this, as_.len(), bs.len()))) diff --git a/src/libstd/either.rs b/src/libstd/either.rs index 132ebc7296011..5d988965e8ccc 100644 --- a/src/libstd/either.rs +++ b/src/libstd/either.rs @@ -16,7 +16,7 @@ use option::{Some, None}; use clone::Clone; use container::Container; use cmp::Eq; -use iterator::Iterator; +use iterator::{Iterator, FilterMap}; use result::Result; use result; use str::StrSlice; @@ -116,40 +116,44 @@ impl Either { } } -// FIXME: #8228 Replaceable by an external iterator? -/// Extracts from a vector of either all the left values -pub fn lefts(eithers: &[Either]) -> ~[L] { - do vec::build_sized(eithers.len()) |push| { - for elt in eithers.iter() { - match *elt { - Left(ref l) => { push((*l).clone()); } - _ => { /* fallthrough */ } - } +/// An iterator yielding the `Left` values of its source +pub type Lefts = FilterMap<'static, Either, L, Iter>; + +/// An iterator yielding the `Right` values of its source +pub type Rights = FilterMap<'static, Either, R, Iter>; + +/// Extracts all the left values +pub fn lefts>>(eithers: Iter) + -> Lefts { + do eithers.filter_map |elt| { + match elt { + Left(x) => Some(x), + _ => None, } } } -// FIXME: #8228 Replaceable by an external iterator? -/// Extracts from a vector of either all the right values -pub fn rights(eithers: &[Either]) -> ~[R] { - do vec::build_sized(eithers.len()) |push| { - for elt in eithers.iter() { - match *elt { - Right(ref r) => { push((*r).clone()); } - _ => { /* fallthrough */ } - } +/// Extracts all the right values +pub fn rights>>(eithers: Iter) + -> Rights { + do eithers.filter_map |elt| { + match elt { + Right(x) => Some(x), + _ => None, } } } + // 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(eithers: ~[Either]) -> (~[L], ~[R]) { - let mut lefts: ~[L] = ~[]; - let mut rights: ~[R] = ~[]; + let n_lefts = eithers.iter().count(|elt| elt.is_left()); + let mut lefts = vec::with_capacity(n_lefts); + let mut rights = vec::with_capacity(eithers.len() - n_lefts); for elt in eithers.move_iter() { match elt { Left(l) => lefts.push(l), @@ -182,42 +186,42 @@ mod tests { #[test] fn test_lefts() { let input = ~[Left(10), Right(11), Left(12), Right(13), Left(14)]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); assert_eq!(result, ~[10, 12, 14]); } #[test] fn test_lefts_none() { let input: ~[Either] = ~[Right(10), Right(10)]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } #[test] fn test_lefts_empty() { let input: ~[Either] = ~[]; - let result = lefts(input); + let result = lefts(input.move_iter()).to_owned_vec(); 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); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result, ~[11, 13]); } #[test] fn test_rights_none() { let input: ~[Either] = ~[Left(10), Left(10)]; - let result = rights(input); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } #[test] fn test_rights_empty() { let input: ~[Either] = ~[]; - let result = rights(input); + let result = rights(input.move_iter()).to_owned_vec(); assert_eq!(result.len(), 0u); } diff --git a/src/libstd/result.rs b/src/libstd/result.rs index 9de5e69148ae9..9ae901d60bc46 100644 --- a/src/libstd/result.rs +++ b/src/libstd/result.rs @@ -18,8 +18,7 @@ use either; use iterator::Iterator; use option::{None, Option, Some, OptionIterator}; use vec; -use vec::{OwnedVector, ImmutableVector}; -use container::Container; +use vec::OwnedVector; use to_str::ToStr; use str::StrSlice; @@ -269,86 +268,76 @@ pub fn map_opt(o_t: &Option, } } -// 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. +/// Takes each element in the iterator: if it is an error, no further +/// elements are taken, and the error is returned. +/// Should no error occur, a vector containing the values of each Result +/// is returned. /// /// Here is an example which increments every integer in a vector, /// checking for overflow: /// -/// fn inc_conditionally(x: uint) -> result { +/// fn inc_conditionally(x: uint) -> Result { /// 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]); -/// } +/// let v = [1u, 2, 3]; +/// let res = collect(v.iter().map(|&x| inc_conditionally(x))); +/// assert!(res == Ok(~[2u, 3, 4])); #[inline] -pub fn map_vec(ts: &[T], op: &fn(&T) -> Result) - -> Result<~[V],U> { - let mut vs: ~[V] = vec::with_capacity(ts.len()); - for t in ts.iter() { - match op(t) { - Ok(v) => vs.push(v), - Err(u) => return Err(u) +pub fn collect>>(mut iterator: Iter) + -> Result<~[T], E> { + let (lower, _) = iterator.size_hint(); + let mut vs: ~[T] = vec::with_capacity(lower); + for t in iterator { + match t { + Ok(v) => vs.push(v), + Err(u) => return Err(u) } } - return Ok(vs); + Ok(vs) } -// FIXME: #8228 Replaceable by an external iterator? -/// Same as map, but it operates over two parallel vectors. +/// Perform a fold operation over the result values from an iterator. /// -/// 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. +/// If an `Err` is encountered, it is immediately returned. +/// Otherwise, the folded value is returned. #[inline] -pub fn map_vec2(ss: &[S], ts: &[T], - op: &fn(&S,&T) -> Result) -> Result<~[V],U> { - assert!(vec::same_length(ss, ts)); - let n = ts.len(); - let mut vs = vec::with_capacity(n); - let mut i = 0u; - while i < n { - match op(&ss[i],&ts[i]) { - Ok(v) => vs.push(v), - Err(u) => return Err(u) +pub fn fold>>( + mut iterator: Iter, + mut init: V, + f: &fn(V, T) -> V) + -> Result { + for t in iterator { + match t { + Ok(v) => init = f(init, v), + Err(u) => return Err(u) } - i += 1u; } - return Ok(vs); + Ok(init) } -// 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. +/// Perform a trivial fold operation over the result values +/// from an iterator. +/// +/// If an `Err` is encountered, it is immediately returned. +/// Otherwise, a simple `Ok(())` is returned. #[inline] -pub fn iter_vec2(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; - while i < n { - match op(&ss[i],&ts[i]) { - Ok(()) => (), - Err(u) => return Err(u) - } - i += 1u; - } - return Ok(()); +pub fn fold_>>( + iterator: Iter) + -> Result<(), E> { + fold(iterator, (), |_, _| ()) } + #[cfg(test)] mod tests { use super::*; use either; + use iterator::range; use str::OwnedStr; + use vec::ImmutableVector; pub fn op1() -> Result { Ok(666) } @@ -431,4 +420,44 @@ mod tests { assert_eq!(r.to_either(), either::Right(100)); assert_eq!(err.to_either(), either::Left(404)); } + + #[test] + fn test_collect() { + assert_eq!(collect(range(0, 0) + .map(|_| Ok::(0))), + Ok(~[])); + assert_eq!(collect(range(0, 3) + .map(|x| Ok::(x))), + Ok(~[0, 1, 2])); + assert_eq!(collect(range(0, 3) + .map(|x| if x > 1 { Err(x) } else { Ok(x) })), + Err(2)); + + // test that it does not take more elements than it needs + let functions = [|| Ok(()), || Err(1), || fail!()]; + + assert_eq!(collect(functions.iter().map(|f| (*f)())), + Err(1)); + } + + #[test] + fn test_fold() { + assert_eq!(fold_(range(0, 0) + .map(|_| Ok::<(), ()>(()))), + Ok(())); + assert_eq!(fold(range(0, 3) + .map(|x| Ok::(x)), + 0, |a, b| a + b), + Ok(3)); + assert_eq!(fold_(range(0, 3) + .map(|x| if x > 1 { Err(x) } else { Ok(()) })), + Err(2)); + + // test that it does not take more elements than it needs + let functions = [|| Ok(()), || Err(1), || fail!()]; + + assert_eq!(fold_(functions.iter() + .map(|f| (*f)())), + Err(1)); + } } diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index b38de31c56a7f..a2664dcf890ad 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -3445,7 +3445,7 @@ impl Parser { |p| p.parse_arg() ); - let inputs = either::lefts(args_or_capture_items); + let inputs = either::lefts(args_or_capture_items.move_iter()).collect(); let (ret_style, ret_ty) = self.parse_ret_ty(); ast::fn_decl { @@ -3608,7 +3608,7 @@ impl Parser { let hi = self.span.hi; - let inputs = either::lefts(args_or_capture_items); + let inputs = either::lefts(args_or_capture_items.move_iter()).collect(); let (ret_style, ret_ty) = self.parse_ret_ty(); let fn_decl = ast::fn_decl { @@ -3641,7 +3641,7 @@ impl Parser { }; ast::fn_decl { - inputs: either::lefts(inputs_captures), + inputs: either::lefts(inputs_captures.move_iter()).collect(), output: output, cf: return_val, }