about summary refs log tree commit diff
path: root/src/libstd/str.rs
diff options
context:
space:
mode:
authorblake2-ppc <blake2-ppc>2013-08-18 13:57:34 +0200
committerblake2-ppc <blake2-ppc>2013-08-19 11:19:59 +0200
commit3cb5b8dc1849c5958c62caf990faf75fcec6b2ea (patch)
treef0c5a6ecd0943f73f44a692c7b7f5bb308a65cb6 /src/libstd/str.rs
parent4043c70f23bbc883088634e9cf0c3224524a2c5c (diff)
std::str: Special case char_range_at_reverse so it is faster
Implement char_range_at_reverse similarly to char_range_at, instead of
re-using that method.
Diffstat (limited to 'src/libstd/str.rs')
-rw-r--r--src/libstd/str.rs34
1 files changed, 21 insertions, 13 deletions
diff --git a/src/libstd/str.rs b/src/libstd/str.rs
index 07006ba8c15..c5c2150617c 100644
--- a/src/libstd/str.rs
+++ b/src/libstd/str.rs
@@ -27,7 +27,7 @@ use iterator::{Iterator, FromIterator, Extendable};
 use iterator::{Filter, AdditiveIterator, Map};
 use iterator::{Invert, DoubleEndedIterator};
 use libc;
-use num::Zero;
+use num::{Saturating, Zero};
 use option::{None, Option, Some};
 use ptr;
 use ptr::RawPtr;
@@ -1698,21 +1698,29 @@ impl<'self> StrSlice<'self> for &'self str {
     fn char_range_at_reverse(&self, start: uint) -> CharRange {
         let mut prev = start;
 
-        // while there is a previous byte == 10......
-        while prev > 0u && self[prev - 1u] & 192u8 == TAG_CONT_U8 {
-            prev -= 1u;
-        }
+        prev = prev.saturating_sub(1);
+        if self[prev] < 128 { return CharRange{ch: self[prev] as char, next: prev} }
 
-        // now refer to the initial byte of previous char
-        if prev > 0u {
-            prev -= 1u;
-        } else {
-            prev = 0u;
-        }
+        // Multibyte case is a fn to allow char_range_at_reverse to inline cleanly
+        fn multibyte_char_range_at_rev(s: &str, mut i: uint) -> CharRange {
+            // while there is a previous byte == 10......
+            while i > 0 && s[i] & 192u8 == TAG_CONT_U8 {
+                i -= 1u;
+            }
+
+            let mut val = s[i] as uint;
+            let w = UTF8_CHAR_WIDTH[val] as uint;
+            assert!((w != 0));
 
+            val = utf8_first_byte!(val, w);
+            val = utf8_acc_cont_byte!(val, s[i + 1]);
+            if w > 2 { val = utf8_acc_cont_byte!(val, s[i + 2]); }
+            if w > 3 { val = utf8_acc_cont_byte!(val, s[i + 3]); }
+
+            return CharRange {ch: val as char, next: i};
+        }
 
-        let ch = self.char_at(prev);
-        return CharRange {ch:ch, next:prev};
+        return multibyte_char_range_at_rev(*self, prev);
     }
 
     /// Plucks the character ending at the `i`th byte of a string