@@ -16,9 +16,8 @@ use str::StrSlice;
1616use str:: OwnedStr ;
1717use container:: Container ;
1818use cast;
19- use ptr;
2019use iter:: Iterator ;
21- use vec:: { CopyableVector , ImmutableVector } ;
20+ use vec:: { CopyableVector , ImmutableVector , MutableVector } ;
2221use to_bytes:: IterBytes ;
2322use option:: { Some , None } ;
2423
@@ -61,7 +60,7 @@ impl Ascii {
6160impl ToStr for Ascii {
6261 #[ inline]
6362 fn to_str ( & self ) -> ~str {
64- // self.chr is allways a valid utf8 byte, no need for the check
63+ // self.chr is always a valid utf8 byte, no need for the check
6564 unsafe { str:: raw:: from_byte ( self . chr ) }
6665 }
6766}
@@ -253,16 +252,29 @@ impl ToBytesConsume for ~[Ascii] {
253252 }
254253}
255254
256- /// Extension methods for ASCII-subset only operations on strings
257- pub trait StrAsciiExt {
255+ /// Extension methods for ASCII-subset only operations on owned strings
256+ pub trait OwnedStrAsciiExt {
258257 /// Convert the string to ASCII upper case:
259258 /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
260259 /// but non-ASCII letters are unchanged.
261- fn to_ascii_upper ( & self ) -> ~str ;
260+ fn into_ascii_upper ( self ) -> ~str ;
262261
263262 /// Convert the string to ASCII lower case:
264263 /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
265264 /// but non-ASCII letters are unchanged.
265+ fn into_ascii_lower ( self ) -> ~str ;
266+ }
267+
268+ /// Extension methods for ASCII-subset only operations on string slices
269+ pub trait StrAsciiExt {
270+ /// Makes a copy of the string in ASCII upper case:
271+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
272+ /// but non-ASCII letters are unchanged.
273+ fn to_ascii_upper ( & self ) -> ~str ;
274+
275+ /// Makes a copy of the string in ASCII lower case:
276+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
277+ /// but non-ASCII letters are unchanged.
266278 fn to_ascii_lower ( & self ) -> ~str ;
267279
268280 /// Check that two strings are an ASCII case-insensitive match.
@@ -274,12 +286,12 @@ pub trait StrAsciiExt {
274286impl < ' self > StrAsciiExt for & ' self str {
275287 #[ inline]
276288 fn to_ascii_upper ( & self ) -> ~str {
277- map_bytes ( * self , ASCII_UPPER_MAP )
289+ unsafe { str_copy_map_bytes ( * self , ASCII_UPPER_MAP ) }
278290 }
279291
280292 #[ inline]
281293 fn to_ascii_lower ( & self ) -> ~str {
282- map_bytes ( * self , ASCII_LOWER_MAP )
294+ unsafe { str_copy_map_bytes ( * self , ASCII_LOWER_MAP ) }
283295 }
284296
285297 #[ inline]
@@ -289,20 +301,34 @@ impl<'self> StrAsciiExt for &'self str {
289301 }
290302}
291303
304+ impl OwnedStrAsciiExt for ~str {
305+ #[ inline]
306+ fn into_ascii_upper ( self ) -> ~str {
307+ unsafe { str_map_bytes ( self , ASCII_UPPER_MAP ) }
308+ }
309+
310+ #[ inline]
311+ fn into_ascii_lower ( self ) -> ~str {
312+ unsafe { str_map_bytes ( self , ASCII_LOWER_MAP ) }
313+ }
314+ }
315+
292316#[ inline]
293- fn map_bytes( string : & str , map : & ' static [ u8 ] ) -> ~str {
294- let len = string. len ( ) ;
295- let mut result = str:: with_capacity ( len) ;
296- unsafe {
297- do result. as_mut_buf |mut buf, _| {
298- for c in string. as_bytes ( ) . iter ( ) {
299- * buf = map[ * c] ;
300- buf = ptr:: mut_offset ( buf, 1 )
301- }
302- }
303- str:: raw:: set_len ( & mut result, len) ;
317+ unsafe fn str_map_bytes ( string : ~str , map : & ' static [ u8 ] ) -> ~str {
318+ let mut bytes = string. into_bytes ( ) ;
319+
320+ for b in bytes. mut_iter ( ) {
321+ * b = map[ * b] ;
304322 }
305- result
323+
324+ str:: raw:: from_utf8_owned ( bytes)
325+ }
326+
327+ #[ inline]
328+ unsafe fn str_copy_map_bytes ( string : & str , map : & ' static [ u8 ] ) -> ~str {
329+ let bytes = string. byte_iter ( ) . map ( |b| map[ b] ) . to_owned_vec ( ) ;
330+
331+ str:: raw:: from_utf8_owned ( bytes)
306332}
307333
308334static ASCII_LOWER_MAP : & ' static [ u8 ] = & [
@@ -494,6 +520,37 @@ mod tests {
494520 }
495521 }
496522
523+ #[test]
524+ fn test_into_ascii_upper() {
525+ assert_eq!((~" url( ) URL ( ) uRl( ) ürl").into_ascii_upper(), ~" URL ( ) URL ( ) URL ( ) üRL");
526+ assert_eq!((~" hıKß").into_ascii_upper(), ~" HıKß ");
527+
528+ let mut i = 0;
529+ while i <= 500 {
530+ let upper = if 'a' as u32 <= i && i <= 'z' as u32 { i + 'A' as u32 - 'a' as u32 }
531+ else { i };
532+ assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_upper(),
533+ from_char(from_u32(upper).unwrap()))
534+ i += 1;
535+ }
536+ }
537+
538+ #[test]
539+ fn test_into_ascii_lower() {
540+ assert_eq!((~" url( ) URL ( ) uRl( ) Ürl").into_ascii_lower(), ~" url( ) url( ) url( ) Ürl");
541+ // Dotted capital I, Kelvin sign, Sharp S.
542+ assert_eq!((~" HİKß ").into_ascii_lower(), ~" hİKß");
543+
544+ let mut i = 0;
545+ while i <= 500 {
546+ let lower = if 'A' as u32 <= i && i <= 'Z' as u32 { i + 'a' as u32 - 'A' as u32 }
547+ else { i };
548+ assert_eq!(from_char(from_u32(i).unwrap()).into_ascii_lower(),
549+ from_char(from_u32(lower).unwrap()))
550+ i += 1;
551+ }
552+ }
553+
497554 #[test]
498555 fn test_eq_ignore_ascii_case() {
499556 assert!(" url( ) URL ( ) uRl( ) Ürl".eq_ignore_ascii_case(" url( ) url( ) url( ) Ürl"));
0 commit comments