@@ -59,6 +59,9 @@ public struct SyntaxText {
59
59
}
60
60
61
61
/// Base address of the memory range this string refers to.
62
+ ///
63
+ /// If the `baseAddress` is `nil`, the text is empty. However, text can be
64
+ /// `isEmpty` even with a non-`nil` base address.
62
65
public var baseAddress : UnsafePointer < UInt8 > ? {
63
66
buffer. baseAddress
64
67
}
@@ -148,10 +151,19 @@ extension SyntaxText: Hashable {
148
151
if lhs. buffer. count != rhs. buffer. count {
149
152
return false
150
153
}
151
- if lhs. isEmpty || lhs. buffer. baseAddress == rhs. buffer. baseAddress {
154
+ guard let lBase = lhs. baseAddress, let rBase = rhs. baseAddress else {
155
+ // If either `baseAddress` is `nil`, both are empty so returns `true`.
152
156
return true
153
157
}
154
- return compareMemory ( lhs. baseAddress!, rhs. baseAddress!, lhs. count)
158
+ // We don't do `lhs.baseAddress == rhs.baseAddress` shortcut, because in
159
+ // SwiftSyntax use cases, comparing the same SyntaxText instances is
160
+ // extremely rare, and checking it causes extra branch.
161
+ // The most common usage is comparing parsed text with a static text e.g.
162
+ // `token.text == "func"`. In such cases `compareMemory`(`memcmp`) is
163
+ // optimzed to a `cmp` or similar opcode if either operand is a short static
164
+ // text. So the same-baseAddress shortcut doesn't give us a huge performance
165
+ // boost even if they actually refer the same memory.
166
+ return compareMemory ( lBase, rBase, lhs. count)
155
167
}
156
168
157
169
public func hash( into hasher: inout Hasher ) {
@@ -209,7 +221,7 @@ extension String {
209
221
private func compareMemory(
210
222
_ s1: UnsafePointer < UInt8 > , _ s2: UnsafePointer < UInt8 > , _ count: Int
211
223
) -> Bool {
212
- assert ( count > 0 )
224
+ assert ( count >= 0 )
213
225
#if canImport(Darwin)
214
226
return Darwin . memcmp ( s1, s2, count) == 0
215
227
#elseif canImport(Glibc)
0 commit comments