@@ -351,89 +351,87 @@ pub const fn is_ascii_simple(mut bytes: &[u8]) -> bool {
351
351
const fn is_ascii ( s : & [ u8 ] ) -> bool {
352
352
// The runtime version behaves the same as the compiletime version, it's
353
353
// 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
+ }
375
372
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 } ;
379
376
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( ) } ;
383
380
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) {
421
382
return false ;
422
383
}
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
+ }
423
426
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 ) ;
433
430
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( ) } ;
436
433
437
- !contains_nonascii ( last_word)
438
- }
434
+ !contains_nonascii( last_word)
435
+ }
436
+ )
439
437
}
0 commit comments