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