@@ -19,33 +19,54 @@ internal func _allASCII(_ input: UnsafeBufferPointer<UInt8>) -> Bool {
1919 //
2020 // TODO(String performance): SIMD-ize
2121 //
22- let ptr = input. baseAddress. _unsafelyUnwrappedUnchecked
23- var i = 0
24-
2522 let count = input. count
26- let stride = MemoryLayout< UInt> . stride
27- let address = Int ( bitPattern: ptr)
28-
29- let wordASCIIMask = UInt ( truncatingIfNeeded: 0x8080_8080_8080_8080 as UInt64 )
30- let byteASCIIMask = UInt8 ( truncatingIfNeeded: wordASCIIMask)
23+ var ptr = UnsafeRawPointer ( input. baseAddress. _unsafelyUnwrappedUnchecked)
24+ var i = 0
3125
32- while ( address &+ i) % stride != 0 && i < count {
33- guard ptr [ i] & byteASCIIMask == 0 else { return false }
34- i &+= 1
26+ let asciiMask64 = 0x8080_8080_8080_8080 as UInt64
27+ let asciiMask32 = UInt32 ( truncatingIfNeeded: asciiMask64)
28+ let asciiMask16 = UInt16 ( truncatingIfNeeded: asciiMask64)
29+ let asciiMask8 = UInt8 ( truncatingIfNeeded: asciiMask64)
30+
31+ let end128 = ptr + count & ~ ( MemoryLayout < ( UInt64 , UInt64 ) > . stride &- 1 )
32+ let end64 = ptr + count & ~ ( MemoryLayout < UInt64 > . stride &- 1 )
33+ let end32 = ptr + count & ~ ( MemoryLayout < UInt32 > . stride &- 1 )
34+ let end16 = ptr + count & ~ ( MemoryLayout < UInt16 > . stride &- 1 )
35+ let end = ptr + count
36+
37+
38+ while ptr < end128 {
39+ let pair = ptr. loadUnaligned ( as: ( UInt64, UInt64) . self)
40+ let result = ( pair. 0 | pair. 1 ) & asciiMask64
41+ guard result == 0 else { return false }
42+ ptr = ptr + MemoryLayout< ( UInt64, UInt64) > . stride
3543 }
36-
37- while ( i &+ stride) <= count {
38- let word : UInt = UnsafePointer (
39- bitPattern: address &+ i
40- ) . _unsafelyUnwrappedUnchecked. pointee
41- guard word & wordASCIIMask == 0 else { return false }
42- i &+= stride
44+
45+ // If we had enough bytes for two iterations of this, we would have hit
46+ // the loop above, so we only need to do this once
47+ if ptr < end64 {
48+ let value = ptr. loadUnaligned ( as: UInt64 . self)
49+ guard value & asciiMask64 == 0 else { return false }
50+ ptr = ptr + MemoryLayout< UInt64> . stride
51+ }
52+
53+ if ptr < end32 {
54+ let value = ptr. loadUnaligned ( as: UInt32 . self)
55+ guard value & asciiMask32 == 0 else { return false }
56+ ptr = ptr + MemoryLayout< UInt32> . stride
57+ }
58+
59+ if ptr < end16 {
60+ let value = ptr. loadUnaligned ( as: UInt16 . self)
61+ guard value & asciiMask16 == 0 else { return false }
62+ ptr = ptr + MemoryLayout< UInt16> . stride
4363 }
4464
45- while i < count {
46- guard ptr [ i ] & byteASCIIMask == 0 else { return false }
47- i &+= 1
65+ if ptr < end {
66+ let value = ptr . loadUnaligned ( fromByteOffset : i , as : UInt8 . self )
67+ guard value & asciiMask8 == 0 else { return false }
4868 }
69+ _internalInvariant ( ptr == end || ptr + 1 == end)
4970 return true
5071}
5172
0 commit comments