1313use to_str:: { ToStr , ToStrConsume } ;
1414use str;
1515use str:: StrSlice ;
16+ use str:: OwnedStr ;
17+ use container:: Container ;
1618use cast;
19+ use ptr;
1720use iterator:: { Iterator , IteratorUtil } ;
1821use vec:: { CopyableVector , ImmutableVector , OwnedVector } ;
1922use to_bytes:: IterBytes ;
@@ -39,27 +42,19 @@ impl Ascii {
3942 /// Convert to lowercase.
4043 #[ inline]
4144 pub fn to_lower ( self ) -> Ascii {
42- if self . chr >= 65 && self . chr <= 90 {
43- Ascii { chr : self . chr | 0x20 }
44- } else {
45- self
46- }
45+ Ascii { chr : ASCII_LOWER_MAP [ self . chr ] }
4746 }
4847
4948 /// Convert to uppercase.
5049 #[ inline]
5150 pub fn to_upper ( self ) -> Ascii {
52- if self . chr >= 97 && self . chr <= 122 {
53- Ascii { chr : self . chr & !0x20 }
54- } else {
55- self
56- }
51+ Ascii { chr : ASCII_UPPER_MAP [ self . chr ] }
5752 }
5853
5954 /// Compares two ascii characters of equality, ignoring case.
6055 #[ inline]
6156 pub fn eq_ignore_case ( self , other : Ascii ) -> bool {
62- self . to_lower ( ) . chr == other. to_lower ( ) . chr
57+ ASCII_LOWER_MAP [ self . chr ] == ASCII_LOWER_MAP [ other. chr ]
6358 }
6459}
6560
@@ -261,10 +256,124 @@ impl ToBytesConsume for ~[Ascii] {
261256 }
262257}
263258
259+
260+ /// Convert the string to ASCII upper case:
261+ /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z',
262+ /// but non-ASCII letters are unchanged.
263+ #[ inline]
264+ pub fn to_ascii_upper ( string : & str ) -> ~str {
265+ map_bytes ( string, ASCII_UPPER_MAP )
266+ }
267+
268+ /// Convert the string to ASCII lower case:
269+ /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z',
270+ /// but non-ASCII letters are unchanged.
271+ #[ inline]
272+ pub fn to_ascii_lower ( string : & str ) -> ~str {
273+ map_bytes ( string, ASCII_LOWER_MAP )
274+ }
275+
276+ #[ inline]
277+ priv fn map_bytes( string : & str , map : & ' static [ u8 ] ) -> ~str {
278+ let len = string. len ( ) ;
279+ let mut result = str:: with_capacity ( len) ;
280+ unsafe {
281+ do result. as_mut_buf |mut buf, _| {
282+ for c in string. as_bytes ( ) . iter ( ) {
283+ * buf = map[ * c] ;
284+ buf = ptr:: mut_offset ( buf, 1 )
285+ }
286+ }
287+ str:: raw:: set_len ( & mut result, len) ;
288+ }
289+ result
290+ }
291+
292+ /// Check that two strings are an ASCII case-insensitive match.
293+ /// Same as `to_ascii_lower(a) == to_ascii_lower(b)`,
294+ /// but without allocating and copying temporary strings.
295+ #[ inline]
296+ pub fn eq_ignore_ascii_case ( a : & str , b : & str ) -> bool {
297+ a. len ( ) == b. len ( ) && a. as_bytes ( ) . iter ( ) . zip ( b. as_bytes ( ) . iter ( ) ) . all (
298+ |( byte_a, byte_b) | ASCII_LOWER_MAP [ * byte_a] == ASCII_LOWER_MAP [ * byte_b] )
299+ }
300+
301+ priv static ASCII_LOWER_MAP : & ' static [ u8 ] = & [
302+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
303+ 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
304+ 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 ,
305+ 0x18 , 0x19 , 0x1a , 0x1b , 0x1c , 0x1d , 0x1e , 0x1f ,
306+ 0x20 , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 , 0x27 ,
307+ 0x28 , 0x29 , 0x2a , 0x2b , 0x2c , 0x2d , 0x2e , 0x2f ,
308+ 0x30 , 0x31 , 0x32 , 0x33 , 0x34 , 0x35 , 0x36 , 0x37 ,
309+ 0x38 , 0x39 , 0x3a , 0x3b , 0x3c , 0x3d , 0x3e , 0x3f ,
310+ 0x40 , 0x61 , 0x62 , 0x63 , 0x64 , 0x65 , 0x66 , 0x67 ,
311+ 0x68 , 0x69 , 0x6a , 0x6b , 0x6c , 0x6d , 0x6e , 0x6f ,
312+ 0x70 , 0x71 , 0x72 , 0x73 , 0x74 , 0x75 , 0x76 , 0x77 ,
313+ 0x78 , 0x79 , 0x7a , 0x5b , 0x5c , 0x5d , 0x5e , 0x5f ,
314+ 0x60 , 0x61 , 0x62 , 0x63 , 0x64 , 0x65 , 0x66 , 0x67 ,
315+ 0x68 , 0x69 , 0x6a , 0x6b , 0x6c , 0x6d , 0x6e , 0x6f ,
316+ 0x70 , 0x71 , 0x72 , 0x73 , 0x74 , 0x75 , 0x76 , 0x77 ,
317+ 0x78 , 0x79 , 0x7a , 0x7b , 0x7c , 0x7d , 0x7e , 0x7f ,
318+ 0x80 , 0x81 , 0x82 , 0x83 , 0x84 , 0x85 , 0x86 , 0x87 ,
319+ 0x88 , 0x89 , 0x8a , 0x8b , 0x8c , 0x8d , 0x8e , 0x8f ,
320+ 0x90 , 0x91 , 0x92 , 0x93 , 0x94 , 0x95 , 0x96 , 0x97 ,
321+ 0x98 , 0x99 , 0x9a , 0x9b , 0x9c , 0x9d , 0x9e , 0x9f ,
322+ 0xa0 , 0xa1 , 0xa2 , 0xa3 , 0xa4 , 0xa5 , 0xa6 , 0xa7 ,
323+ 0xa8 , 0xa9 , 0xaa , 0xab , 0xac , 0xad , 0xae , 0xaf ,
324+ 0xb0 , 0xb1 , 0xb2 , 0xb3 , 0xb4 , 0xb5 , 0xb6 , 0xb7 ,
325+ 0xb8 , 0xb9 , 0xba , 0xbb , 0xbc , 0xbd , 0xbe , 0xbf ,
326+ 0xc0 , 0xc1 , 0xc2 , 0xc3 , 0xc4 , 0xc5 , 0xc6 , 0xc7 ,
327+ 0xc8 , 0xc9 , 0xca , 0xcb , 0xcc , 0xcd , 0xce , 0xcf ,
328+ 0xd0 , 0xd1 , 0xd2 , 0xd3 , 0xd4 , 0xd5 , 0xd6 , 0xd7 ,
329+ 0xd8 , 0xd9 , 0xda , 0xdb , 0xdc , 0xdd , 0xde , 0xdf ,
330+ 0xe0 , 0xe1 , 0xe2 , 0xe3 , 0xe4 , 0xe5 , 0xe6 , 0xe7 ,
331+ 0xe8 , 0xe9 , 0xea , 0xeb , 0xec , 0xed , 0xee , 0xef ,
332+ 0xf0 , 0xf1 , 0xf2 , 0xf3 , 0xf4 , 0xf5 , 0xf6 , 0xf7 ,
333+ 0xf8 , 0xf9 , 0xfa , 0xfb , 0xfc , 0xfd , 0xfe , 0xff ,
334+ ] ;
335+
336+ priv static ASCII_UPPER_MAP : & ' static [ u8 ] = & [
337+ 0x00 , 0x01 , 0x02 , 0x03 , 0x04 , 0x05 , 0x06 , 0x07 ,
338+ 0x08 , 0x09 , 0x0a , 0x0b , 0x0c , 0x0d , 0x0e , 0x0f ,
339+ 0x10 , 0x11 , 0x12 , 0x13 , 0x14 , 0x15 , 0x16 , 0x17 ,
340+ 0x18 , 0x19 , 0x1a , 0x1b , 0x1c , 0x1d , 0x1e , 0x1f ,
341+ 0x20 , 0x21 , 0x22 , 0x23 , 0x24 , 0x25 , 0x26 , 0x27 ,
342+ 0x28 , 0x29 , 0x2a , 0x2b , 0x2c , 0x2d , 0x2e , 0x2f ,
343+ 0x30 , 0x31 , 0x32 , 0x33 , 0x34 , 0x35 , 0x36 , 0x37 ,
344+ 0x38 , 0x39 , 0x3a , 0x3b , 0x3c , 0x3d , 0x3e , 0x3f ,
345+ 0x40 , 0x41 , 0x42 , 0x43 , 0x44 , 0x45 , 0x46 , 0x47 ,
346+ 0x48 , 0x49 , 0x4a , 0x4b , 0x4c , 0x4d , 0x4e , 0x4f ,
347+ 0x50 , 0x51 , 0x52 , 0x53 , 0x54 , 0x55 , 0x56 , 0x57 ,
348+ 0x58 , 0x59 , 0x5a , 0x5b , 0x5c , 0x5d , 0x5e , 0x5f ,
349+ 0x60 , 0x41 , 0x42 , 0x43 , 0x44 , 0x45 , 0x46 , 0x47 ,
350+ 0x48 , 0x49 , 0x4a , 0x4b , 0x4c , 0x4d , 0x4e , 0x4f ,
351+ 0x50 , 0x51 , 0x52 , 0x53 , 0x54 , 0x55 , 0x56 , 0x57 ,
352+ 0x58 , 0x59 , 0x5a , 0x7b , 0x7c , 0x7d , 0x7e , 0x7f ,
353+ 0x80 , 0x81 , 0x82 , 0x83 , 0x84 , 0x85 , 0x86 , 0x87 ,
354+ 0x88 , 0x89 , 0x8a , 0x8b , 0x8c , 0x8d , 0x8e , 0x8f ,
355+ 0x90 , 0x91 , 0x92 , 0x93 , 0x94 , 0x95 , 0x96 , 0x97 ,
356+ 0x98 , 0x99 , 0x9a , 0x9b , 0x9c , 0x9d , 0x9e , 0x9f ,
357+ 0xa0 , 0xa1 , 0xa2 , 0xa3 , 0xa4 , 0xa5 , 0xa6 , 0xa7 ,
358+ 0xa8 , 0xa9 , 0xaa , 0xab , 0xac , 0xad , 0xae , 0xaf ,
359+ 0xb0 , 0xb1 , 0xb2 , 0xb3 , 0xb4 , 0xb5 , 0xb6 , 0xb7 ,
360+ 0xb8 , 0xb9 , 0xba , 0xbb , 0xbc , 0xbd , 0xbe , 0xbf ,
361+ 0xc0 , 0xc1 , 0xc2 , 0xc3 , 0xc4 , 0xc5 , 0xc6 , 0xc7 ,
362+ 0xc8 , 0xc9 , 0xca , 0xcb , 0xcc , 0xcd , 0xce , 0xcf ,
363+ 0xd0 , 0xd1 , 0xd2 , 0xd3 , 0xd4 , 0xd5 , 0xd6 , 0xd7 ,
364+ 0xd8 , 0xd9 , 0xda , 0xdb , 0xdc , 0xdd , 0xde , 0xdf ,
365+ 0xe0 , 0xe1 , 0xe2 , 0xe3 , 0xe4 , 0xe5 , 0xe6 , 0xe7 ,
366+ 0xe8 , 0xe9 , 0xea , 0xeb , 0xec , 0xed , 0xee , 0xef ,
367+ 0xf0 , 0xf1 , 0xf2 , 0xf3 , 0xf4 , 0xf5 , 0xf6 , 0xf7 ,
368+ 0xf8 , 0xf9 , 0xfa , 0xfb , 0xfc , 0xfd , 0xfe , 0xff ,
369+ ] ;
370+
371+
264372#[ cfg( test) ]
265373mod tests {
266374 use super :: * ;
267375 use to_bytes:: ToBytes ;
376+ use str:: from_char;
268377
269378 macro_rules! v2ascii (
270379 ( [ $( $e: expr) ,* ] ) => ( [ $( Ascii { chr: $e} ) ,* ] ) ;
@@ -347,4 +456,53 @@ mod tests {
347456
348457 #[test] #[should_fail]
349458 fn test_ascii_fail_char_slice() { 'λ'.to_ascii(); }
459+
460+ #[test]
461+ fn test_to_ascii_upper() {
462+ assert_eq!(to_ascii_upper(" url( ) URL ( ) uRl( ) ürl"), ~" URL ( ) URL ( ) URL ( ) üRL");
463+ assert_eq!(to_ascii_upper(" hıKß"), ~" HıKß ");
464+
465+ let mut i = 0;
466+ while i <= 500 {
467+ let c = i as char;
468+ let upper = if 'a' <= c && c <= 'z' { c + 'A' - 'a' } else { c };
469+ assert_eq!(to_ascii_upper(from_char(i as char)), from_char(upper))
470+ i += 1;
471+ }
472+ }
473+
474+ #[test]
475+ fn test_to_ascii_lower() {
476+ assert_eq!(to_ascii_lower(" url( ) URL ( ) uRl( ) Ürl"), ~" url( ) url( ) url( ) Ürl");
477+ // Dotted capital I, Kelvin sign, Sharp S.
478+ assert_eq!(to_ascii_lower(" HİKß "), ~" hİKß");
479+
480+ let mut i = 0;
481+ while i <= 500 {
482+ let c = i as char;
483+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c };
484+ assert_eq!(to_ascii_lower(from_char(i as char)), from_char(lower))
485+ i += 1;
486+ }
487+ }
488+
489+
490+ #[test]
491+ fn test_eq_ignore_ascii_case() {
492+ assert!(eq_ignore_ascii_case(" url( ) URL ( ) uRl( ) Ürl", " url( ) url( ) url( ) Ürl"));
493+ assert!(!eq_ignore_ascii_case(" Ürl", " ürl"));
494+ // Dotted capital I, Kelvin sign, Sharp S.
495+ assert!(eq_ignore_ascii_case(" HİKß ", " hİKß"));
496+ assert!(!eq_ignore_ascii_case(" İ", " i"));
497+ assert!(!eq_ignore_ascii_case(" K", " k"));
498+ assert!(!eq_ignore_ascii_case(" ß", " s" ) ) ;
499+
500+ let mut i = 0 ;
501+ while i <= 500 {
502+ let c = i as char ;
503+ let lower = if 'A' <= c && c <= 'Z' { c + 'a' - 'A' } else { c } ;
504+ assert!( eq_ignore_ascii_case( from_char( i as char ) , from_char( lower) ) ) ;
505+ i += 1 ;
506+ }
507+ }
350508}
0 commit comments