File tree Expand file tree Collapse file tree 3 files changed +58
-10
lines changed Expand file tree Collapse file tree 3 files changed +58
-10
lines changed Original file line number Diff line number Diff line change @@ -268,6 +268,24 @@ const fn contains_nonascii(v: usize) -> bool {
268268 ( NONASCII_MASK & v) != 0
269269}
270270
271+ /// ASCII test *without* the chunk-at-a-time optimizations.
272+ ///
273+ /// This is carefully structured to produce nice small code -- it's smaller in
274+ /// `-O` than what the "obvious" ways produces under `-C opt-level=s`. If you
275+ /// touch it, be sure to run (and update if needed) the assembly test.
276+ #[ unstable( feature = "str_internals" , issue = "none" ) ]
277+ #[ doc( hidden) ]
278+ #[ inline]
279+ pub const fn is_ascii_simple ( mut bytes : & [ u8 ] ) -> bool {
280+ while let [ rest @ .., last] = bytes {
281+ if !last. is_ascii ( ) {
282+ break ;
283+ }
284+ bytes = rest;
285+ }
286+ bytes. is_empty ( )
287+ }
288+
271289/// Optimized ASCII test that will use usize-at-a-time operations instead of
272290/// byte-at-a-time operations (when possible).
273291///
@@ -293,16 +311,7 @@ const fn is_ascii(s: &[u8]) -> bool {
293311 // We also do this for architectures where `size_of::<usize>()` isn't
294312 // sufficient alignment for `usize`, because it's a weird edge case.
295313 if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem:: align_of :: < usize > ( ) {
296- // FIXME: once iterators and closures can be used in `const fn`,
297- // return s.iter().all(|b| b.is_ascii());
298- let mut i = 0 ;
299- while i < len {
300- if !s[ i] . is_ascii ( ) {
301- return false ;
302- }
303- i += 1 ;
304- }
305- return true ;
314+ return is_ascii_simple ( s) ;
306315 }
307316
308317 // We always read the first word unaligned, which means `align_offset` is
Original file line number Diff line number Diff line change @@ -44,6 +44,10 @@ mod raw;
4444mod rotate;
4545mod specialize;
4646
47+ #[ unstable( feature = "str_internals" , issue = "none" ) ]
48+ #[ doc( hidden) ]
49+ pub use ascii:: is_ascii_simple;
50+
4751#[ stable( feature = "rust1" , since = "1.0.0" ) ]
4852pub use iter:: { Chunks , ChunksMut , Windows } ;
4953#[ stable( feature = "rust1" , since = "1.0.0" ) ]
Original file line number Diff line number Diff line change 1+ // revisions: WIN LIN
2+ // [WIN] only-windows
3+ // [LIN] only-linux
4+ // assembly-output: emit-asm
5+ // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel
6+ // min-llvm-version: 14
7+ // only-x86_64
8+ // ignore-sgx
9+ // ignore-debug
10+
11+ #![ feature( str_internals) ]
12+
13+ // CHECK-LABEL: is_ascii_simple_demo:
14+ #[ no_mangle]
15+ pub fn is_ascii_simple_demo ( bytes : & [ u8 ] ) -> bool {
16+ // Linux (System V): pointer is rdi; length is rsi
17+ // Windows: pointer is rcx; length is rdx.
18+
19+ // CHECK-NOT: mov
20+ // CHECK-NOT: test
21+ // CHECK-NOT: cmp
22+
23+ // CHECK: .[[LOOPHEAD:.+]]:
24+ // CHECK-NEXT: mov [[TEMP:.+]], [[LEN:rsi|rdx]]
25+ // CHECK-NEXT: sub [[LEN]], 1
26+ // CHECK-NEXT: jb .[[LOOPEXIT:.+]]
27+ // CHECK-NEXT: cmp byte ptr [{{rdi|rcx}} + [[TEMP]] - 1], 0
28+ // CHECK-NEXT: jns .[[LOOPHEAD]]
29+
30+ // CHECK-NEXT: .[[LOOPEXIT]]:
31+ // CHECK-NEXT: test [[TEMP]], [[TEMP]]
32+ // CHECK-NEXT: sete al
33+ // CHECK-NEXT: ret
34+ core:: slice:: is_ascii_simple ( bytes)
35+ }
You can’t perform that action at this time.
0 commit comments