Skip to content

Commit 0038b92

Browse files
authored
Speed up -isEqual:/isEqualToString: (#83894)
Fixes rdar://159058877
1 parent 825a626 commit 0038b92

File tree

2 files changed

+35
-14
lines changed

2 files changed

+35
-14
lines changed

stdlib/public/core/StringBridge.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ internal typealias _CocoaString = AnyObject
6262
@objc(newTaggedNSStringWithASCIIBytes_:length_:)
6363
func createTaggedString(bytes: UnsafePointer<UInt8>,
6464
count: Int) -> AnyObject?
65+
66+
@objc(isNSString__)
67+
func getIsNSString() -> Int8
6568
}
6669

6770
/*
@@ -105,9 +108,15 @@ internal func _stdlib_binary_CFStringGetLength(
105108
return _NSStringLen(_objc(source))
106109
}
107110

111+
@_effects(readonly) private func isNSStringImpl(
112+
_ str: _StringSelectorHolder
113+
) -> Bool {
114+
return str.getIsNSString() != 0
115+
}
116+
108117
@_effects(readonly)
109118
internal func _isNSString(_ str:AnyObject) -> Bool {
110-
return _swift_stdlib_isNSString(str) != 0
119+
return isNSStringImpl(_objc(str))
111120
}
112121

113122
@_effects(readonly)

stdlib/public/core/StringStorageBridge.swift

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -158,21 +158,25 @@ extension _AbstractStringStorage {
158158

159159
// At this point we've proven that it is a non-Swift NSString
160160
let otherUTF16Length = _stdlib_binary_CFStringGetLength(other)
161-
161+
162+
if UTF16Length != otherUTF16Length {
163+
return 0
164+
}
165+
162166
// CFString will only give us ASCII bytes here, but that's fine.
163167
// We already handled non-ASCII UTF8 strings earlier since they're Swift.
164168
if let asciiEqual = unsafe withCocoaASCIIPointer(other, work: { (ascii) -> Bool in
165-
// UTF16 length == UTF8 length iff ASCII
166-
if otherUTF16Length == self.count {
167-
return unsafe (start == ascii || (memcmp(start, ascii, self.count) == 0))
168-
}
169-
return false
169+
return unsafe (start == ascii || (memcmp(start, ascii, self.count) == 0))
170170
}) {
171171
return asciiEqual ? 1 : 0
172172
}
173-
174-
if self.UTF16Length != otherUTF16Length {
175-
return 0
173+
174+
if let utf16Ptr = unsafe _stdlib_binary_CFStringGetCharactersPtr(other) {
175+
let utf16Buffer = unsafe UnsafeBufferPointer(
176+
start: utf16Ptr,
177+
count: otherUTF16Length
178+
)
179+
return unsafe asString.utf16.elementsEqual(utf16Buffer) ? 1 : 0
176180
}
177181

178182
/*
@@ -189,7 +193,11 @@ extension __StringStorage {
189193
@objc(length)
190194
final internal var UTF16Length: Int {
191195
@_effects(readonly) @inline(__always) get {
192-
return asString.utf16.count // UTF16View special-cases ASCII for us.
196+
// UTF16View does this, but there's still a little overhead
197+
if isASCII {
198+
return count
199+
}
200+
return asString.utf16.count
193201
}
194202
}
195203

@@ -235,7 +243,7 @@ extension __StringStorage {
235243
_ requiresNulTermination: Int8,
236244
_ outUTF8Length: UnsafeMutablePointer<UInt>
237245
) -> UnsafePointer<UInt8>? {
238-
outUTF8Length.pointee = UInt(count)
246+
unsafe outUTF8Length.pointee = UInt(count)
239247
return unsafe start
240248
}
241249

@@ -301,7 +309,11 @@ extension __SharedStringStorage {
301309
@objc(length)
302310
final internal var UTF16Length: Int {
303311
@_effects(readonly) get {
304-
return asString.utf16.count // UTF16View special-cases ASCII for us.
312+
// UTF16View does this, but there's still a little overhead
313+
if isASCII {
314+
return count
315+
}
316+
return asString.utf16.count
305317
}
306318
}
307319

@@ -363,7 +375,7 @@ extension __SharedStringStorage {
363375
_ requiresNulTermination: Int8,
364376
_ outUTF8Length: UnsafeMutablePointer<UInt>
365377
) -> UnsafePointer<UInt8>? {
366-
outUTF8Length.pointee = UInt(count)
378+
unsafe outUTF8Length.pointee = UInt(count)
367379
return unsafe start
368380
}
369381

0 commit comments

Comments
 (0)