about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorHuon Wilson <dbau.pp+github@gmail.com>2013-06-11 23:52:24 +1000
committerHuon Wilson <dbau.pp+github@gmail.com>2013-06-12 12:21:04 +1000
commit073e82fff27497ea9b7b73173ddfc349463570b7 (patch)
tree20b77711bc0728cea9b468083725e795e801617d /src
parent3a1e13c7a00cd5cc90385d1fc577a992a155bd34 (diff)
downloadrust-073e82fff27497ea9b7b73173ddfc349463570b7.tar.gz
rust-073e82fff27497ea9b7b73173ddfc349463570b7.zip
std: create Str trait for DRY. Use it on StrVector.
The Str trait collects the various strings types and provides a method
for coercing to a slice, so that functions and impls can be written for
generic types containing strings (e.g. &[~str], &[&str], ...) without
having to write one for each string type (assuming that the impl only
needs a slice).
Diffstat (limited to 'src')
-rw-r--r--src/libstd/str.rs117
1 files changed, 32 insertions, 85 deletions
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 5da0301c52a..ef3d77ee5e7 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -26,7 +26,7 @@ use clone::Clone;
 use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
 use container::Container;
 use iter::Times;
-use iterator::{Iterator, IteratorUtil, FilterIterator};
+use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator};
 use libc;
 use option::{None, Option, Some};
 use old_iter::{BaseIter, EqIter};
@@ -160,87 +160,13 @@ pub trait StrVector {
     pub fn connect(&self, sep: &str) -> ~str;
 }
 
-impl<'self> StrVector for &'self [~str] {
+impl<'self, S: Str> StrVector for &'self [S] {
     /// 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 = ~"";
+        let len = self.iter().transform(|s| s.as_slice().len()).sum();
 
-        s.reserve(len);
-
-        unsafe {
-            do as_buf(s) |buf, _| {
-                let mut buf = ::cast::transmute_mut_unsafe(buf);
-                for self.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(&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;
-
-        s.reserve(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
-    }
-}
-
-impl<'self> StrVector for &'self [&'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 = ~"";
 
         s.reserve(len);
@@ -248,8 +174,8 @@ impl<'self> StrVector for &'self [&'self str] {
         unsafe {
             do as_buf(s) |buf, _| {
                 let mut buf = ::cast::transmute_mut_unsafe(buf);
-                for self.each |ss| {
-                    do as_buf(*ss) |ssbuf, sslen| {
+                for self.iter().advance |ss| {
+                    do as_buf(ss.as_slice()) |ssbuf, sslen| {
                         let sslen = sslen - 1;
                         ptr::copy_memory(buf, ssbuf, sslen);
                         buf = buf.offset(sslen);
@@ -269,10 +195,8 @@ impl<'self> StrVector for &'self [&'self str] {
         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 len = sep.len() * (self.len() - 1)
+            + self.iter().transform(|s| s.as_slice().len()).sum();
         let mut s = ~"";
         let mut first = true;
 
@@ -283,8 +207,8 @@ impl<'self> StrVector for &'self [&'self str] {
                 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| {
+                    for self.iter().advance |ss| {
+                        do as_buf(ss.as_slice()) |ssbuf, sslen| {
                             let sslen = sslen - 1;
                             if first {
                                 first = false;
@@ -1267,6 +1191,29 @@ pub mod traits {
 #[cfg(test)]
 pub mod traits {}
 
+/// Any string that can be represented as a slice
+pub trait Str {
+    /// Work with `self` as a slice.
+    fn as_slice<'a>(&'a self) -> &'a str;
+}
+
+impl<'self> Str for &'self str {
+    #[inline(always)]
+    fn as_slice<'a>(&'a self) -> &'a str { *self }
+}
+impl<'self> Str for ~str {
+    #[inline(always)]
+    fn as_slice<'a>(&'a self) -> &'a str {
+        let s: &'a str = *self; s
+    }
+}
+impl<'self> Str for @str {
+    #[inline(always)]
+    fn as_slice<'a>(&'a self) -> &'a str {
+        let s: &'a str = *self; s
+    }
+}
+
 #[allow(missing_doc)]
 pub trait StrSlice<'self> {
     fn contains<'a>(&self, needle: &'a str) -> bool;