about summary refs log tree commit diff
diff options
context:
space:
mode:
authorroot <root@localhost>2014-08-23 12:30:08 +0200
committerroot <root@localhost>2014-08-23 13:49:19 +0200
commitb3b7c2e97b8e34ebc2597c21653df4b2d7a37575 (patch)
tree1353cdc9d2cc4cdfd2e523610c6acf0b4ed3e451
parent58bb603ea74a388d7a4dafc0c78f214a46301505 (diff)
downloadrust-b3b7c2e97b8e34ebc2597c21653df4b2d7a37575.tar.gz
rust-b3b7c2e97b8e34ebc2597c21653df4b2d7a37575.zip
core: Separate failure formatting in str methods slice, slice_to, slice_from
Use a separate inline-never function to format failure message for
str::slice() errors.

Using strcat's idea, this makes sure no formatting code from failure is
inlined when str::slice() is inlined. The number of `unreachable` being
inlined when usingi `.slice()` drops from 5 to just 1.
-rw-r--r--src/libcore/str.rs42
1 files changed, 31 insertions, 11 deletions
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index 076eb8bbe6a..1ba958cd211 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -1705,6 +1705,13 @@ pub trait StrSlice<'a> {
     fn utf16_units(&self) -> Utf16CodeUnits<'a>;
 }
 
+#[inline(never)]
+fn slice_error_fail(s: &str, begin: uint, end: uint) -> ! {
+    assert!(begin <= end);
+    fail!("index {} and/or {} in `{}` do not lie on character boundary",
+          begin, end, s);
+}
+
 impl<'a> StrSlice<'a> for &'a str {
     #[inline]
     fn contains<'a>(&self, needle: &'a str) -> bool {
@@ -1808,22 +1815,34 @@ impl<'a> StrSlice<'a> for &'a str {
 
     #[inline]
     fn slice(&self, begin: uint, end: uint) -> &'a str {
-        assert!(self.is_char_boundary(begin) && self.is_char_boundary(end),
-                "index {} and/or {} in `{}` do not lie on character boundary", begin,
-                end, *self);
-        unsafe { raw::slice_bytes(*self, begin, end) }
+        // is_char_boundary checks that the index is in [0, .len()]
+        if begin <= end &&
+           self.is_char_boundary(begin) &&
+           self.is_char_boundary(end) {
+            unsafe { raw::slice_unchecked(*self, begin, end) }
+        } else {
+            slice_error_fail(*self, begin, end)
+        }
     }
 
     #[inline]
     fn slice_from(&self, begin: uint) -> &'a str {
-        self.slice(begin, self.len())
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(begin) {
+            unsafe { raw::slice_unchecked(*self, begin, self.len()) }
+        } else {
+            slice_error_fail(*self, begin, self.len())
+        }
     }
 
     #[inline]
     fn slice_to(&self, end: uint) -> &'a str {
-        assert!(self.is_char_boundary(end), "index {} in `{}` does not lie on \
-                a character boundary", end, *self);
-        unsafe { raw::slice_bytes(*self, 0, end) }
+        // is_char_boundary checks that the index is in [0, .len()]
+        if self.is_char_boundary(end) {
+            unsafe { raw::slice_unchecked(*self, 0, end) }
+        } else {
+            slice_error_fail(*self, 0, end)
+        }
     }
 
     fn slice_chars(&self, begin: uint, end: uint) -> &'a str {
@@ -1898,9 +1917,10 @@ impl<'a> StrSlice<'a> for &'a str {
     #[inline]
     fn is_char_boundary(&self, index: uint) -> bool {
         if index == self.len() { return true; }
-        if index > self.len() { return false; }
-        let b = self.as_bytes()[index];
-        return b < 128u8 || b >= 192u8;
+        match self.as_bytes().get(index) {
+            None => false,
+            Some(&b) => b < 128u8 || b >= 192u8,
+        }
     }
 
     #[inline]