@@ -369,89 +369,87 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
369
369
const fn is_ascii ( s : & [ u8 ] ) -> bool {
370
370
// The runtime version behaves the same as the compiletime version, it's
371
371
// just more optimized.
372
- return const_eval_select ( ( s, ) , compiletime, runtime) ;
373
-
374
- const fn compiletime ( s : & [ u8 ] ) -> bool {
375
- is_ascii_simple ( s)
376
- }
377
-
378
- #[ inline]
379
- fn runtime ( s : & [ u8 ] ) -> bool {
380
- const USIZE_SIZE : usize = mem:: size_of :: < usize > ( ) ;
381
-
382
- let len = s. len ( ) ;
383
- let align_offset = s. as_ptr ( ) . align_offset ( USIZE_SIZE ) ;
384
-
385
- // If we wouldn't gain anything from the word-at-a-time implementation, fall
386
- // back to a scalar loop.
387
- //
388
- // We also do this for architectures where `size_of::<usize>()` isn't
389
- // sufficient alignment for `usize`, because it's a weird edge case.
390
- if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem:: align_of :: < usize > ( ) {
391
- return is_ascii_simple ( s) ;
392
- }
372
+ const_eval_select ! (
373
+ @capture { s: & [ u8 ] } -> bool :
374
+ if const {
375
+ is_ascii_simple( s)
376
+ } else {
377
+ const USIZE_SIZE : usize = mem:: size_of:: <usize >( ) ;
378
+
379
+ let len = s. len( ) ;
380
+ let align_offset = s. as_ptr( ) . align_offset( USIZE_SIZE ) ;
381
+
382
+ // If we wouldn't gain anything from the word-at-a-time implementation, fall
383
+ // back to a scalar loop.
384
+ //
385
+ // We also do this for architectures where `size_of::<usize>()` isn't
386
+ // sufficient alignment for `usize`, because it's a weird edge case.
387
+ if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem:: align_of:: <usize >( ) {
388
+ return is_ascii_simple( s) ;
389
+ }
393
390
394
- // We always read the first word unaligned, which means `align_offset` is
395
- // 0, we'd read the same value again for the aligned read.
396
- let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset } ;
391
+ // We always read the first word unaligned, which means `align_offset` is
392
+ // 0, we'd read the same value again for the aligned read.
393
+ let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset } ;
397
394
398
- let start = s. as_ptr ( ) ;
399
- // SAFETY: We verify `len < USIZE_SIZE` above.
400
- let first_word = unsafe { ( start as * const usize ) . read_unaligned ( ) } ;
395
+ let start = s. as_ptr( ) ;
396
+ // SAFETY: We verify `len < USIZE_SIZE` above.
397
+ let first_word = unsafe { ( start as * const usize ) . read_unaligned( ) } ;
401
398
402
- if contains_nonascii ( first_word) {
403
- return false ;
404
- }
405
- // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
406
- // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
407
- // above.
408
- debug_assert ! ( offset_to_aligned <= len) ;
409
-
410
- // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
411
- // middle chunk of the slice.
412
- let mut word_ptr = unsafe { start. add ( offset_to_aligned) as * const usize } ;
413
-
414
- // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
415
- let mut byte_pos = offset_to_aligned;
416
-
417
- // Paranoia check about alignment, since we're about to do a bunch of
418
- // unaligned loads. In practice this should be impossible barring a bug in
419
- // `align_offset` though.
420
- // While this method is allowed to spuriously fail in CTFE, if it doesn't
421
- // have alignment information it should have given a `usize::MAX` for
422
- // `align_offset` earlier, sending things through the scalar path instead of
423
- // this one, so this check should pass if it's reachable.
424
- debug_assert ! ( word_ptr. is_aligned_to( mem:: align_of:: <usize >( ) ) ) ;
425
-
426
- // Read subsequent words until the last aligned word, excluding the last
427
- // aligned word by itself to be done in tail check later, to ensure that
428
- // tail is always one `usize` at most to extra branch `byte_pos == len`.
429
- while byte_pos < len - USIZE_SIZE {
430
- // Sanity check that the read is in bounds
431
- debug_assert ! ( byte_pos + USIZE_SIZE <= len) ;
432
- // And that our assumptions about `byte_pos` hold.
433
- debug_assert ! ( word_ptr. cast:: <u8 >( ) == start. wrapping_add( byte_pos) ) ;
434
-
435
- // SAFETY: We know `word_ptr` is properly aligned (because of
436
- // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
437
- let word = unsafe { word_ptr. read ( ) } ;
438
- if contains_nonascii ( word) {
399
+ if contains_nonascii( first_word) {
439
400
return false ;
440
401
}
402
+ // We checked this above, somewhat implicitly. Note that `offset_to_aligned`
403
+ // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked
404
+ // above.
405
+ debug_assert!( offset_to_aligned <= len) ;
406
+
407
+ // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the
408
+ // middle chunk of the slice.
409
+ let mut word_ptr = unsafe { start. add( offset_to_aligned) as * const usize } ;
410
+
411
+ // `byte_pos` is the byte index of `word_ptr`, used for loop end checks.
412
+ let mut byte_pos = offset_to_aligned;
413
+
414
+ // Paranoia check about alignment, since we're about to do a bunch of
415
+ // unaligned loads. In practice this should be impossible barring a bug in
416
+ // `align_offset` though.
417
+ // While this method is allowed to spuriously fail in CTFE, if it doesn't
418
+ // have alignment information it should have given a `usize::MAX` for
419
+ // `align_offset` earlier, sending things through the scalar path instead of
420
+ // this one, so this check should pass if it's reachable.
421
+ debug_assert!( word_ptr. is_aligned_to( mem:: align_of:: <usize >( ) ) ) ;
422
+
423
+ // Read subsequent words until the last aligned word, excluding the last
424
+ // aligned word by itself to be done in tail check later, to ensure that
425
+ // tail is always one `usize` at most to extra branch `byte_pos == len`.
426
+ while byte_pos < len - USIZE_SIZE {
427
+ // Sanity check that the read is in bounds
428
+ debug_assert!( byte_pos + USIZE_SIZE <= len) ;
429
+ // And that our assumptions about `byte_pos` hold.
430
+ debug_assert!( word_ptr. cast:: <u8 >( ) == start. wrapping_add( byte_pos) ) ;
431
+
432
+ // SAFETY: We know `word_ptr` is properly aligned (because of
433
+ // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end
434
+ let word = unsafe { word_ptr. read( ) } ;
435
+ if contains_nonascii( word) {
436
+ return false ;
437
+ }
438
+
439
+ byte_pos += USIZE_SIZE ;
440
+ // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
441
+ // after this `add`, `word_ptr` will be at most one-past-the-end.
442
+ word_ptr = unsafe { word_ptr. add( 1 ) } ;
443
+ }
441
444
442
- byte_pos += USIZE_SIZE ;
443
- // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that
444
- // after this `add`, `word_ptr` will be at most one-past-the-end.
445
- word_ptr = unsafe { word_ptr. add ( 1 ) } ;
446
- }
447
-
448
- // Sanity check to ensure there really is only one `usize` left. This should
449
- // be guaranteed by our loop condition.
450
- debug_assert ! ( byte_pos <= len && len - byte_pos <= USIZE_SIZE ) ;
445
+ // Sanity check to ensure there really is only one `usize` left. This should
446
+ // be guaranteed by our loop condition.
447
+ debug_assert!( byte_pos <= len && len - byte_pos <= USIZE_SIZE ) ;
451
448
452
- // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
453
- let last_word = unsafe { ( start. add ( len - USIZE_SIZE ) as * const usize ) . read_unaligned ( ) } ;
449
+ // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start.
450
+ let last_word = unsafe { ( start. add( len - USIZE_SIZE ) as * const usize ) . read_unaligned( ) } ;
454
451
455
- !contains_nonascii ( last_word)
456
- }
452
+ !contains_nonascii( last_word)
453
+ }
454
+ )
457
455
}
0 commit comments