File tree 3 files changed +58
-10
lines changed
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 {
268
268
( NONASCII_MASK & v) != 0
269
269
}
270
270
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
+
271
289
/// Optimized ASCII test that will use usize-at-a-time operations instead of
272
290
/// byte-at-a-time operations (when possible).
273
291
///
@@ -293,16 +311,7 @@ const fn is_ascii(s: &[u8]) -> bool {
293
311
// We also do this for architectures where `size_of::<usize>()` isn't
294
312
// sufficient alignment for `usize`, because it's a weird edge case.
295
313
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) ;
306
315
}
307
316
308
317
// 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;
44
44
mod rotate;
45
45
mod specialize;
46
46
47
+ #[ unstable( feature = "str_internals" , issue = "none" ) ]
48
+ #[ doc( hidden) ]
49
+ pub use ascii:: is_ascii_simple;
50
+
47
51
#[ stable( feature = "rust1" , since = "1.0.0" ) ]
48
52
pub use iter:: { Chunks , ChunksMut , Windows } ;
49
53
#[ 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