Skip to content

Commit 408c2f7

Browse files
committed
Auto merge of #37926 - bluss:from-utf8-small-simplification, r=sfackler
UTF-8 validation: Compute block end upfront Simplify the conditional used for ensuring that the whole word loop is only used if there are at least two whole words left to read. This makes the function slightly smaller and simpler, a 0-5% reduction in runtime for various test cases.
2 parents 2782e8f + 0dffc1e commit 408c2f7

File tree

1 file changed

+26
-27
lines changed

1 file changed

+26
-27
lines changed

src/libcore/str/mod.rs

+26-27
Original file line numberDiff line numberDiff line change
@@ -1232,26 +1232,31 @@ fn contains_nonascii(x: usize) -> bool {
12321232
/// invalid sequence.
12331233
#[inline(always)]
12341234
fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
1235-
let mut offset = 0;
1235+
let mut index = 0;
12361236
let len = v.len();
1237-
while offset < len {
1238-
let old_offset = offset;
1237+
1238+
let usize_bytes = mem::size_of::<usize>();
1239+
let ascii_block_size = 2 * usize_bytes;
1240+
let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 };
1241+
1242+
while index < len {
1243+
let old_offset = index;
12391244
macro_rules! err { () => {{
12401245
return Err(Utf8Error {
12411246
valid_up_to: old_offset
12421247
})
12431248
}}}
12441249

12451250
macro_rules! next { () => {{
1246-
offset += 1;
1251+
index += 1;
12471252
// we needed data, but there was none: error!
1248-
if offset >= len {
1253+
if index >= len {
12491254
err!()
12501255
}
1251-
v[offset]
1256+
v[index]
12521257
}}}
12531258

1254-
let first = v[offset];
1259+
let first = v[index];
12551260
if first >= 128 {
12561261
let w = UTF8_CHAR_WIDTH[first as usize];
12571262
let second = next!();
@@ -1294,38 +1299,32 @@ fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> {
12941299
}
12951300
_ => err!()
12961301
}
1297-
offset += 1;
1302+
index += 1;
12981303
} else {
12991304
// Ascii case, try to skip forward quickly.
13001305
// When the pointer is aligned, read 2 words of data per iteration
13011306
// until we find a word containing a non-ascii byte.
1302-
let usize_bytes = mem::size_of::<usize>();
1303-
let bytes_per_iteration = 2 * usize_bytes;
13041307
let ptr = v.as_ptr();
1305-
let align = (ptr as usize + offset) & (usize_bytes - 1);
1308+
let align = (ptr as usize + index) & (usize_bytes - 1);
13061309
if align == 0 {
1307-
if len >= bytes_per_iteration {
1308-
while offset <= len - bytes_per_iteration {
1309-
unsafe {
1310-
let u = *(ptr.offset(offset as isize) as *const usize);
1311-
let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize);
1312-
1313-
// break if there is a nonascii byte
1314-
let zu = contains_nonascii(u);
1315-
let zv = contains_nonascii(v);
1316-
if zu || zv {
1317-
break;
1318-
}
1310+
while index < blocks_end {
1311+
unsafe {
1312+
let block = ptr.offset(index as isize) as *const usize;
1313+
// break if there is a nonascii byte
1314+
let zu = contains_nonascii(*block);
1315+
let zv = contains_nonascii(*block.offset(1));
1316+
if zu | zv {
1317+
break;
13191318
}
1320-
offset += bytes_per_iteration;
13211319
}
1320+
index += ascii_block_size;
13221321
}
13231322
// step from the point where the wordwise loop stopped
1324-
while offset < len && v[offset] < 128 {
1325-
offset += 1;
1323+
while index < len && v[index] < 128 {
1324+
index += 1;
13261325
}
13271326
} else {
1328-
offset += 1;
1327+
index += 1;
13291328
}
13301329
}
13311330
}

0 commit comments

Comments
 (0)