Skip to content

Commit d0c3142

Browse files
committed
auto merge of rust-lang#16698 : bluss/rust/slice-bloat, r=huonw
These are somewhat stop-gap solutions to address rust-lang#16625 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. The testcase: ``` #![crate_type = "lib"] pub fn slice(x: &str, a: uint, b: uint) -> &str { x.slice(a, b) } ``` shrinks from 16.9 kB to 3.3 kB llvm IR, and the number of `unreachable` drops from 5 to 1.
2 parents 904d88c + b3b7c2e commit d0c3142

File tree

1 file changed

+31
-11
lines changed

1 file changed

+31
-11
lines changed

src/libcore/str.rs

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1717,6 +1717,13 @@ pub trait StrSlice<'a> {
17171717
fn utf16_units(&self) -> Utf16CodeUnits<'a>;
17181718
}
17191719

1720+
#[inline(never)]
1721+
fn slice_error_fail(s: &str, begin: uint, end: uint) -> ! {
1722+
assert!(begin <= end);
1723+
fail!("index {} and/or {} in `{}` do not lie on character boundary",
1724+
begin, end, s);
1725+
}
1726+
17201727
impl<'a> StrSlice<'a> for &'a str {
17211728
#[inline]
17221729
fn contains<'a>(&self, needle: &'a str) -> bool {
@@ -1820,22 +1827,34 @@ impl<'a> StrSlice<'a> for &'a str {
18201827

18211828
#[inline]
18221829
fn slice(&self, begin: uint, end: uint) -> &'a str {
1823-
assert!(self.is_char_boundary(begin) && self.is_char_boundary(end),
1824-
"index {} and/or {} in `{}` do not lie on character boundary", begin,
1825-
end, *self);
1826-
unsafe { raw::slice_bytes(*self, begin, end) }
1830+
// is_char_boundary checks that the index is in [0, .len()]
1831+
if begin <= end &&
1832+
self.is_char_boundary(begin) &&
1833+
self.is_char_boundary(end) {
1834+
unsafe { raw::slice_unchecked(*self, begin, end) }
1835+
} else {
1836+
slice_error_fail(*self, begin, end)
1837+
}
18271838
}
18281839

18291840
#[inline]
18301841
fn slice_from(&self, begin: uint) -> &'a str {
1831-
self.slice(begin, self.len())
1842+
// is_char_boundary checks that the index is in [0, .len()]
1843+
if self.is_char_boundary(begin) {
1844+
unsafe { raw::slice_unchecked(*self, begin, self.len()) }
1845+
} else {
1846+
slice_error_fail(*self, begin, self.len())
1847+
}
18321848
}
18331849

18341850
#[inline]
18351851
fn slice_to(&self, end: uint) -> &'a str {
1836-
assert!(self.is_char_boundary(end), "index {} in `{}` does not lie on \
1837-
a character boundary", end, *self);
1838-
unsafe { raw::slice_bytes(*self, 0, end) }
1852+
// is_char_boundary checks that the index is in [0, .len()]
1853+
if self.is_char_boundary(end) {
1854+
unsafe { raw::slice_unchecked(*self, 0, end) }
1855+
} else {
1856+
slice_error_fail(*self, 0, end)
1857+
}
18391858
}
18401859

18411860
fn slice_chars(&self, begin: uint, end: uint) -> &'a str {
@@ -1910,9 +1929,10 @@ impl<'a> StrSlice<'a> for &'a str {
19101929
#[inline]
19111930
fn is_char_boundary(&self, index: uint) -> bool {
19121931
if index == self.len() { return true; }
1913-
if index > self.len() { return false; }
1914-
let b = self.as_bytes()[index];
1915-
return b < 128u8 || b >= 192u8;
1932+
match self.as_bytes().get(index) {
1933+
None => false,
1934+
Some(&b) => b < 128u8 || b >= 192u8,
1935+
}
19161936
}
19171937

19181938
#[inline]

0 commit comments

Comments
 (0)