Skip to content

Commit 073e82f

Browse files
committed
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).
1 parent 3a1e13c commit 073e82f

File tree

1 file changed

+32
-85
lines changed

1 file changed

+32
-85
lines changed

src/libstd/str.rs

Lines changed: 32 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use clone::Clone;
2626
use cmp::{TotalOrd, Ordering, Less, Equal, Greater};
2727
use container::Container;
2828
use iter::Times;
29-
use iterator::{Iterator, IteratorUtil, FilterIterator};
29+
use iterator::{Iterator, IteratorUtil, FilterIterator, AdditiveIterator};
3030
use libc;
3131
use option::{None, Option, Some};
3232
use old_iter::{BaseIter, EqIter};
@@ -160,96 +160,22 @@ pub trait StrVector {
160160
pub fn connect(&self, sep: &str) -> ~str;
161161
}
162162

163-
impl<'self> StrVector for &'self [~str] {
163+
impl<'self, S: Str> StrVector for &'self [S] {
164164
/// Concatenate a vector of strings.
165165
pub fn concat(&self) -> ~str {
166166
if self.is_empty() { return ~""; }
167167

168-
let mut len = 0;
169-
for self.each |ss| {
170-
len += ss.len();
171-
}
172-
let mut s = ~"";
168+
let len = self.iter().transform(|s| s.as_slice().len()).sum();
173169

174-
s.reserve(len);
175-
176-
unsafe {
177-
do as_buf(s) |buf, _| {
178-
let mut buf = ::cast::transmute_mut_unsafe(buf);
179-
for self.each |ss| {
180-
do as_buf(*ss) |ssbuf, sslen| {
181-
let sslen = sslen - 1;
182-
ptr::copy_memory(buf, ssbuf, sslen);
183-
buf = buf.offset(sslen);
184-
}
185-
}
186-
}
187-
raw::set_len(&mut s, len);
188-
}
189-
s
190-
}
191-
192-
/// Concatenate a vector of strings, placing a given separator between each.
193-
pub fn connect(&self, sep: &str) -> ~str {
194-
if self.is_empty() { return ~""; }
195-
196-
// concat is faster
197-
if sep.is_empty() { return self.concat(); }
198-
199-
// this is wrong without the guarantee that `self` is non-empty
200-
let mut len = sep.len() * (self.len() - 1);
201-
for self.each |ss| {
202-
len += ss.len();
203-
}
204-
let mut s = ~"";
205-
let mut first = true;
206-
207-
s.reserve(len);
208-
209-
unsafe {
210-
do as_buf(s) |buf, _| {
211-
do as_buf(sep) |sepbuf, seplen| {
212-
let seplen = seplen - 1;
213-
let mut buf = ::cast::transmute_mut_unsafe(buf);
214-
for self.each |ss| {
215-
do as_buf(*ss) |ssbuf, sslen| {
216-
let sslen = sslen - 1;
217-
if first {
218-
first = false;
219-
} else {
220-
ptr::copy_memory(buf, sepbuf, seplen);
221-
buf = buf.offset(seplen);
222-
}
223-
ptr::copy_memory(buf, ssbuf, sslen);
224-
buf = buf.offset(sslen);
225-
}
226-
}
227-
}
228-
}
229-
raw::set_len(&mut s, len);
230-
}
231-
s
232-
}
233-
}
234-
235-
impl<'self> StrVector for &'self [&'self str] {
236-
/// Concatenate a vector of strings.
237-
pub fn concat(&self) -> ~str {
238-
if self.is_empty() { return ~""; }
239-
240-
let mut len = 0;
241-
for self.each |ss| {
242-
len += ss.len();
243-
}
244170
let mut s = ~"";
245171

246172
s.reserve(len);
247173

248174
unsafe {
249175
do as_buf(s) |buf, _| {
250176
let mut buf = ::cast::transmute_mut_unsafe(buf);
251-
for self.each |ss| {
252-
do as_buf(*ss) |ssbuf, sslen| {
177+
for self.iter().advance |ss| {
178+
do as_buf(ss.as_slice()) |ssbuf, sslen| {
253179
let sslen = sslen - 1;
254180
ptr::copy_memory(buf, ssbuf, sslen);
255181
buf = buf.offset(sslen);
@@ -269,10 +195,8 @@ impl<'self> StrVector for &'self [&'self str] {
269195
if sep.is_empty() { return self.concat(); }
270196

271197
// this is wrong without the guarantee that `self` is non-empty
272-
let mut len = sep.len() * (self.len() - 1);
273-
for self.each |ss| {
274-
len += ss.len();
275-
}
198+
let len = sep.len() * (self.len() - 1)
199+
+ self.iter().transform(|s| s.as_slice().len()).sum();
276200
let mut s = ~"";
277201
let mut first = true;
278202

@@ -283,8 +207,8 @@ impl<'self> StrVector for &'self [&'self str] {
283207
do as_buf(sep) |sepbuf, seplen| {
284208
let seplen = seplen - 1;
285209
let mut buf = ::cast::transmute_mut_unsafe(buf);
286-
for self.each |ss| {
287-
do as_buf(*ss) |ssbuf, sslen| {
210+
for self.iter().advance |ss| {
211+
do as_buf(ss.as_slice()) |ssbuf, sslen| {
288212
let sslen = sslen - 1;
289213
if first {
290214
first = false;
@@ -1267,6 +1191,29 @@ pub mod traits {
12671191
#[cfg(test)]
12681192
pub mod traits {}
12691193
1194+
/// Any string that can be represented as a slice
1195+
pub trait Str {
1196+
/// Work with `self` as a slice.
1197+
fn as_slice<'a>(&'a self) -> &'a str;
1198+
}
1199+
1200+
impl<'self> Str for &'self str {
1201+
#[inline(always)]
1202+
fn as_slice<'a>(&'a self) -> &'a str { *self }
1203+
}
1204+
impl<'self> Str for ~str {
1205+
#[inline(always)]
1206+
fn as_slice<'a>(&'a self) -> &'a str {
1207+
let s: &'a str = *self; s
1208+
}
1209+
}
1210+
impl<'self> Str for @str {
1211+
#[inline(always)]
1212+
fn as_slice<'a>(&'a self) -> &'a str {
1213+
let s: &'a str = *self; s
1214+
}
1215+
}
1216+
12701217
#[allow(missing_doc)]
12711218
pub trait StrSlice<'self> {
12721219
fn contains<'a>(&self, needle: &'a str) -> bool;

0 commit comments

Comments
 (0)