@@ -19,33 +19,54 @@ internal func _allASCII(_ input: UnsafeBufferPointer<UInt8>) -> Bool {
19
19
//
20
20
// TODO(String performance): SIMD-ize
21
21
//
22
- let ptr = input. baseAddress. _unsafelyUnwrappedUnchecked
23
- var i = 0
24
-
25
22
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
31
25
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
35
43
}
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
43
63
}
44
64
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 }
48
68
}
69
+ _internalInvariant ( ptr == end || ptr + 1 == end)
49
70
return true
50
71
}
51
72
0 commit comments