Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add traits for concat and connect methods #6908

Merged
merged 1 commit into from
Jun 3, 2013
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Add traits for concat and connect methods
  • Loading branch information
brendanzab committed Jun 3, 2013
commit dee7c5af6991b02c86e6a84b57551fd5cc71caaf
4 changes: 2 additions & 2 deletions src/libstd/prelude.rs
Original file line number Diff line number Diff line change
@@ -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};
212 changes: 141 additions & 71 deletions src/libstd/str.rs
Original file line number Diff line number Diff line change
@@ -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");
78 changes: 61 additions & 17 deletions src/libstd/vec.rs
Original file line number Diff line number Diff line change
@@ -1011,26 +1011,58 @@ pub fn retain<T>(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<T:Copy>(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<T:Copy>(v: &[~[T]]) -> ~[T] { v.concat() }

/// Concatenate a vector of vectors, placing a given separator between each
pub fn connect<T:Copy>(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<T:Copy>(v: &[&[T]]) -> ~[T] { v.concat() }

/// Concatenate a vector of vectors, placing a given separator between each
pub fn connect<T:Copy>(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<T:Copy>(v: &[&[T]], sep: &T) -> ~[T] { v.connect(sep) }

#[allow(missing_doc)]
pub trait VectorVector<T> {
pub fn concat(&self) -> ~[T];
pub fn connect(&self, sep: &T) -> ~[T];
}

impl<'self, T:Copy> VectorVector<T> 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<T> 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,13 +3973,25 @@ 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]
fn test_connect() {
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]