diff --git a/src/libstd/prelude.rs b/src/libstd/prelude.rs index 5a5efa0781ae9..87430e3390a3c 100644 --- a/src/libstd/prelude.rs +++ b/src/libstd/prelude.rs @@ -45,7 +45,7 @@ pub use path::PosixPath; pub use path::WindowsPath; pub use ptr::Ptr; pub use ascii::{Ascii, AsciiCast, OwnedAsciiCast, AsciiStr}; -pub use str::{StrSlice, OwnedStr, StrUtil}; +pub use str::{StrVector, StrSlice, OwnedStr, StrUtil}; pub use from_str::{FromStr}; pub use to_bytes::IterBytes; pub use to_str::{ToStr, ToStrConsume}; @@ -56,7 +56,7 @@ pub use tuple::{CloneableTuple10, CloneableTuple11, CloneableTuple12}; pub use tuple::{ImmutableTuple2, ImmutableTuple3, ImmutableTuple4, ImmutableTuple5}; pub use tuple::{ImmutableTuple6, ImmutableTuple7, ImmutableTuple8, ImmutableTuple9}; pub use tuple::{ImmutableTuple10, ImmutableTuple11, ImmutableTuple12}; -pub use vec::{CopyableVector, ImmutableVector}; +pub use vec::{VectorVector, CopyableVector, ImmutableVector}; pub use vec::{ImmutableEqVector, ImmutableCopyableVector}; pub use vec::{OwnedVector, OwnedCopyableVector, MutableVector}; pub use io::{Reader, ReaderUtil, Writer, WriterUtil}; diff --git a/src/libstd/str.rs b/src/libstd/str.rs index c9452ed543364..961d93823add9 100644 --- a/src/libstd/str.rs +++ b/src/libstd/str.rs @@ -241,110 +241,165 @@ pub fn append(lhs: ~str, rhs: &str) -> ~str { } /// Concatenate a vector of strings -pub fn concat(v: &[~str]) -> ~str { - if v.is_empty() { return ~""; } +pub fn concat(v: &[~str]) -> ~str { v.concat() } - let mut len = 0; - for v.each |ss| { - len += ss.len(); - } - let mut s = ~""; - - reserve(&mut s, len); +/// Concatenate a vector of strings +pub fn concat_slices(v: &[&str]) -> ~str { v.concat() } - unsafe { - do as_buf(s) |buf, _len| { - let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { - do as_buf(*ss) |ssbuf, sslen| { - let sslen = sslen - 1; - ptr::copy_memory(buf, ssbuf, sslen); - buf = buf.offset(sslen); - } - } - } - raw::set_len(&mut s, len); - } - s -} +/// Concatenate a vector of strings, placing a given separator between each +pub fn connect(v: &[~str], sep: &str) -> ~str { v.connect(sep) } /// Concatenate a vector of strings, placing a given separator between each -pub fn connect(v: &[~str], sep: &str) -> ~str { - if v.is_empty() { return ~""; } +pub fn connect_slices(v: &[&str], sep: &str) -> ~str { v.connect(sep) } - // concat is faster - if sep.is_empty() { return concat(v); } +#[allow(missing_doc)] +pub trait StrVector { + pub fn concat(&self) -> ~str; + pub fn connect(&self, sep: &str) -> ~str; +} - // this is wrong without the guarantee that v is non-empty - let mut len = sep.len() * (v.len() - 1); - for v.each |ss| { - len += ss.len(); - } - let mut s = ~"", first = true; +impl<'self> StrVector for &'self [~str] { + /// Concatenate a vector of strings. + pub fn concat(&self) -> ~str { + if self.is_empty() { return ~""; } + + let mut len = 0; + for self.each |ss| { + len += ss.len(); + } + let mut s = ~""; - reserve(&mut s, len); + reserve(&mut s, len); - unsafe { - do as_buf(s) |buf, _len| { - do as_buf(sep) |sepbuf, seplen| { - let seplen = seplen - 1; + unsafe { + do as_buf(s) |buf, _| { let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { + for self.each |ss| { do as_buf(*ss) |ssbuf, sslen| { let sslen = sslen - 1; - if first { - first = false; - } else { - ptr::copy_memory(buf, sepbuf, seplen); - buf = buf.offset(seplen); - } ptr::copy_memory(buf, ssbuf, sslen); buf = buf.offset(sslen); } } } + raw::set_len(&mut s, len); } - raw::set_len(&mut s, len); + s } - s -} -/// Concatenate a vector of strings, placing a given separator between each -pub fn connect_slices(v: &[&str], sep: &str) -> ~str { - if v.is_empty() { return ~""; } + /// Concatenate a vector of strings, placing a given separator between each. + pub fn connect(&self, sep: &str) -> ~str { + if self.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return self.concat(); } - // this is wrong without the guarantee that v is non-empty - let mut len = sep.len() * (v.len() - 1); - for v.each |ss| { - len += ss.len(); + // this is wrong without the guarantee that `self` is non-empty + let mut len = sep.len() * (self.len() - 1); + for self.each |ss| { + len += ss.len(); + } + let mut s = ~""; + let mut first = true; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for self.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); + } + s } - let mut s = ~"", first = true; +} - reserve(&mut s, len); +impl<'self> StrVector for &'self [&'self str] { + /// Concatenate a vector of strings. + pub fn concat(&self) -> ~str { + if self.is_empty() { return ~""; } - unsafe { - do as_buf(s) |buf, _len| { - do as_buf(sep) |sepbuf, seplen| { - let seplen = seplen - 1; + let mut len = 0; + for self.each |ss| { + len += ss.len(); + } + let mut s = ~""; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _| { let mut buf = ::cast::transmute_mut_unsafe(buf); - for v.each |ss| { + for self.each |ss| { do as_buf(*ss) |ssbuf, sslen| { let sslen = sslen - 1; - if first { - first = false; - } else if seplen > 0 { - ptr::copy_memory(buf, sepbuf, seplen); - buf = buf.offset(seplen); - } ptr::copy_memory(buf, ssbuf, sslen); buf = buf.offset(sslen); } } } + raw::set_len(&mut s, len); } - raw::set_len(&mut s, len); + s + } + + /// Concatenate a vector of strings, placing a given separator between each. + pub fn connect(&self, sep: &str) -> ~str { + if self.is_empty() { return ~""; } + + // concat is faster + if sep.is_empty() { return self.concat(); } + + // this is wrong without the guarantee that `self` is non-empty + let mut len = sep.len() * (self.len() - 1); + for self.each |ss| { + len += ss.len(); + } + let mut s = ~""; + let mut first = true; + + reserve(&mut s, len); + + unsafe { + do as_buf(s) |buf, _| { + do as_buf(sep) |sepbuf, seplen| { + let seplen = seplen - 1; + let mut buf = ::cast::transmute_mut_unsafe(buf); + for self.each |ss| { + do as_buf(*ss) |ssbuf, sslen| { + let sslen = sslen - 1; + if first { + first = false; + } else { + ptr::copy_memory(buf, sepbuf, seplen); + buf = buf.offset(seplen); + } + ptr::copy_memory(buf, ssbuf, sslen); + buf = buf.offset(sslen); + } + } + } + } + raw::set_len(&mut s, len); + } + s } - s } /// Given a string, make a new string with repeated copies of it @@ -3184,6 +3239,7 @@ mod tests { fn test_concat() { fn t(v: &[~str], s: &str) { assert_eq!(concat(v), s.to_str()); + assert_eq!(v.concat(), s.to_str()); } t([~"you", ~"know", ~"I'm", ~"no", ~"good"], "youknowI'mnogood"); let v: &[~str] = []; @@ -3195,6 +3251,7 @@ mod tests { fn test_connect() { fn t(v: &[~str], sep: &str, s: &str) { assert_eq!(connect(v, sep), s.to_str()); + assert_eq!(v.connect(sep), s.to_str()); } t([~"you", ~"know", ~"I'm", ~"no", ~"good"], " ", "you know I'm no good"); @@ -3203,10 +3260,23 @@ mod tests { t([~"hi"], " ", "hi"); } + #[test] + fn test_concat_slices() { + fn t(v: &[&str], s: &str) { + assert_eq!(concat_slices(v), s.to_str()); + assert_eq!(v.concat(), s.to_str()); + } + t(["you", "know", "I'm", "no", "good"], "youknowI'mnogood"); + let v: &[&str] = []; + t(v, ""); + t(["hi"], "hi"); + } + #[test] fn test_connect_slices() { fn t(v: &[&str], sep: &str, s: &str) { assert_eq!(connect_slices(v, sep), s.to_str()); + assert_eq!(v.connect(sep), s.to_str()); } t(["you", "know", "I'm", "no", "good"], " ", "you know I'm no good"); diff --git a/src/libstd/vec.rs b/src/libstd/vec.rs index 8eedb70b3a6f4..b748ca54cf425 100644 --- a/src/libstd/vec.rs +++ b/src/libstd/vec.rs @@ -1011,26 +1011,58 @@ pub fn retain(v: &mut ~[T], f: &fn(t: &T) -> bool) { } } -/** - * Concatenate a vector of vectors. - * - * Flattens a vector of vectors of T into a single vector of T. - */ -pub fn concat(v: &[~[T]]) -> ~[T] { - let mut r = ~[]; - for each(v) |inner| { r.push_all(*inner); } - r -} +/// Flattens a vector of vectors of T into a single vector of T. +pub fn concat(v: &[~[T]]) -> ~[T] { v.concat() } + +/// Concatenate a vector of vectors, placing a given separator between each +pub fn connect(v: &[~[T]], sep: &T) -> ~[T] { v.connect(sep) } + +/// Flattens a vector of vectors of T into a single vector of T. +pub fn concat_slices(v: &[&[T]]) -> ~[T] { v.concat() } /// Concatenate a vector of vectors, placing a given separator between each -pub fn connect(v: &[~[T]], sep: &T) -> ~[T] { - let mut r: ~[T] = ~[]; - let mut first = true; - for each(v) |inner| { - if first { first = false; } else { r.push(*sep); } - r.push_all(*inner); +pub fn connect_slices(v: &[&[T]], sep: &T) -> ~[T] { v.connect(sep) } + +#[allow(missing_doc)] +pub trait VectorVector { + pub fn concat(&self) -> ~[T]; + pub fn connect(&self, sep: &T) -> ~[T]; +} + +impl<'self, T:Copy> VectorVector for &'self [~[T]] { + /// Flattens a vector of slices of T into a single vector of T. + pub fn concat(&self) -> ~[T] { + self.flat_map(|&inner| inner) + } + + /// Concatenate a vector of vectors, placing a given separator between each. + pub fn connect(&self, sep: &T) -> ~[T] { + let mut r = ~[]; + let mut first = true; + for self.each |&inner| { + if first { first = false; } else { r.push(*sep); } + r.push_all(inner); + } + r + } +} + +impl<'self, T:Copy> VectorVector for &'self [&'self [T]] { + /// Flattens a vector of slices of T into a single vector of T. + pub fn concat(&self) -> ~[T] { + self.flat_map(|&inner| inner.to_owned()) + } + + /// Concatenate a vector of slices, placing a given separator between each. + pub fn connect(&self, sep: &T) -> ~[T] { + let mut r = ~[]; + let mut first = true; + for self.each |&inner| { + if first { first = false; } else { r.push(*sep); } + r.push_all(inner); + } + r } - r } /** @@ -3941,6 +3973,10 @@ mod tests { #[test] fn test_concat() { assert_eq!(concat([~[1], ~[2,3]]), ~[1, 2, 3]); + assert_eq!([~[1], ~[2,3]].concat(), ~[1, 2, 3]); + + assert_eq!(concat_slices([&[1], &[2,3]]), ~[1, 2, 3]); + assert_eq!([&[1], &[2,3]].concat(), ~[1, 2, 3]); } #[test] @@ -3948,6 +3984,14 @@ mod tests { assert_eq!(connect([], &0), ~[]); assert_eq!(connect([~[1], ~[2, 3]], &0), ~[1, 0, 2, 3]); assert_eq!(connect([~[1], ~[2], ~[3]], &0), ~[1, 0, 2, 0, 3]); + assert_eq!([~[1], ~[2, 3]].connect(&0), ~[1, 0, 2, 3]); + assert_eq!([~[1], ~[2], ~[3]].connect(&0), ~[1, 0, 2, 0, 3]); + + assert_eq!(connect_slices([], &0), ~[]); + assert_eq!(connect_slices([&[1], &[2, 3]], &0), ~[1, 0, 2, 3]); + assert_eq!(connect_slices([&[1], &[2], &[3]], &0), ~[1, 0, 2, 0, 3]); + assert_eq!([&[1], &[2, 3]].connect(&0), ~[1, 0, 2, 3]); + assert_eq!([&[1], &[2], &[3]].connect(&0), ~[1, 0, 2, 0, 3]); } #[test]