]> git.lizzy.rs Git - rust.git/blob - library/core/benches/ascii/is_ascii.rs
Rollup merge of #107148 - Ezrashaw:uncode-e0789, r=compiler-errors,GuillaumeGomez
[rust.git] / library / core / benches / ascii / is_ascii.rs
1 use super::{LONG, MEDIUM, SHORT};
2 use test::black_box;
3 use test::Bencher;
4
5 macro_rules! benches {
6     ($( fn $name: ident($arg: ident: &[u8]) $body: block )+) => {
7         benches!(mod short SHORT[..] $($name $arg $body)+);
8         benches!(mod medium MEDIUM[..] $($name $arg $body)+);
9         benches!(mod long LONG[..] $($name $arg $body)+);
10         // Ensure we benchmark cases where the functions are called with strings
11         // that are not perfectly aligned or have a length which is not a
12         // multiple of size_of::<usize>() (or both)
13         benches!(mod unaligned_head MEDIUM[1..] $($name $arg $body)+);
14         benches!(mod unaligned_tail MEDIUM[..(MEDIUM.len() - 1)] $($name $arg $body)+);
15         benches!(mod unaligned_both MEDIUM[1..(MEDIUM.len() - 1)] $($name $arg $body)+);
16     };
17
18     (mod $mod_name: ident $input: ident [$range: expr] $($name: ident $arg: ident $body: block)+) => {
19         mod $mod_name {
20             use super::*;
21             $(
22                 #[bench]
23                 fn $name(bencher: &mut Bencher) {
24                     bencher.bytes = $input[$range].len() as u64;
25                     let mut vec = $input.as_bytes().to_vec();
26                     bencher.iter(|| {
27                         let $arg: &[u8] = &black_box(&mut vec)[$range];
28                         black_box($body)
29                     })
30                 }
31             )+
32         }
33     };
34 }
35
36 benches! {
37     fn case00_libcore(bytes: &[u8]) {
38         bytes.is_ascii()
39     }
40
41     fn case01_iter_all(bytes: &[u8]) {
42         bytes.iter().all(|b| b.is_ascii())
43     }
44
45     fn case02_align_to(bytes: &[u8]) {
46         is_ascii_align_to(bytes)
47     }
48
49     fn case03_align_to_unrolled(bytes: &[u8]) {
50         is_ascii_align_to_unrolled(bytes)
51     }
52 }
53
54 // These are separate since it's easier to debug errors if they don't go through
55 // macro expansion first.
56 fn is_ascii_align_to(bytes: &[u8]) -> bool {
57     if bytes.len() < core::mem::size_of::<usize>() {
58         return bytes.iter().all(|b| b.is_ascii());
59     }
60     // SAFETY: transmuting a sequence of `u8` to `usize` is always fine
61     let (head, body, tail) = unsafe { bytes.align_to::<usize>() };
62     head.iter().all(|b| b.is_ascii())
63         && body.iter().all(|w| !contains_nonascii(*w))
64         && tail.iter().all(|b| b.is_ascii())
65 }
66
67 fn is_ascii_align_to_unrolled(bytes: &[u8]) -> bool {
68     if bytes.len() < core::mem::size_of::<usize>() {
69         return bytes.iter().all(|b| b.is_ascii());
70     }
71     // SAFETY: transmuting a sequence of `u8` to `[usize; 2]` is always fine
72     let (head, body, tail) = unsafe { bytes.align_to::<[usize; 2]>() };
73     head.iter().all(|b| b.is_ascii())
74         && body.iter().all(|w| !contains_nonascii(w[0] | w[1]))
75         && tail.iter().all(|b| b.is_ascii())
76 }
77
78 #[inline]
79 fn contains_nonascii(v: usize) -> bool {
80     const NONASCII_MASK: usize = usize::from_ne_bytes([0x80; core::mem::size_of::<usize>()]);
81     (NONASCII_MASK & v) != 0
82 }