13
13
use to_str:: { ToStr , ToStrConsume } ;
14
14
use str;
15
15
use str:: StrSlice ;
16
+ use str:: OwnedStr ;
17
+ use container:: Container ;
16
18
use cast;
19
+ use ptr;
17
20
use iterator:: { Iterator , IteratorUtil } ;
18
21
use vec:: { CopyableVector , ImmutableVector , OwnedVector } ;
19
22
use to_bytes:: IterBytes ;
@@ -39,27 +42,19 @@ impl Ascii {
39
42
/// Convert to lowercase.
40
43
#[ inline]
41
44
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 ] }
47
46
}
48
47
49
48
/// Convert to uppercase.
50
49
#[ inline]
51
50
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 ] }
57
52
}
58
53
59
54
/// Compares two ascii characters of equality, ignoring case.
60
55
#[ inline]
61
56
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 ]
63
58
}
64
59
}
65
60
@@ -261,10 +256,124 @@ impl ToBytesConsume for ~[Ascii] {
261
256
}
262
257
}
263
258
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
+
264
372
#[ cfg( test) ]
265
373
mod tests {
266
374
use super :: * ;
267
375
use to_bytes:: ToBytes ;
376
+ use str:: from_char;
268
377
269
378
macro_rules! v2ascii (
270
379
( [ $( $e: expr) ,* ] ) => ( [ $( Ascii { chr: $e} ) ,* ] ) ;
@@ -347,4 +456,53 @@ mod tests {
347
456
348
457
#[test] #[should_fail]
349
458
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
+ }
350
508
}
0 commit comments