Skip to content

Commit 3945260

Browse files
milsemanairspeedswift
authored andcommitted
[5.0] String performance and code size improvements (#21081)
* [String] In-register smol ASCII string compare Compare small strings in-register when they store ASCII (and thus NFC) contents. * [String] String-from-whole-Substring fast-path. Add in a fast-path for Strings created from Substring which covers the entire String. Put String-from-Substring behind a non-inlinable resilience barrier for future flexibility.
1 parent 7ec471b commit 3945260

File tree

4 files changed

+38
-1
lines changed

4 files changed

+38
-1
lines changed

stdlib/public/core/StringComparison.swift

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,31 @@ internal func _stringCompare(
1818
_ lhs: _StringGuts, _ rhs: _StringGuts, expecting: _StringComparisonResult
1919
) -> Bool {
2020
if lhs.rawBits == rhs.rawBits { return expecting == .equal }
21+
return _stringCompareWithSmolCheck(lhs, rhs, expecting: expecting)
22+
}
23+
24+
@usableFromInline
25+
@_effects(readonly)
26+
internal func _stringCompareWithSmolCheck(
27+
_ lhs: _StringGuts, _ rhs: _StringGuts, expecting: _StringComparisonResult
28+
) -> Bool {
29+
// ASCII small-string fast-path:
30+
if lhs.isSmallASCII && rhs.isSmallASCII {
31+
let lhsRaw = lhs.asSmall._storage
32+
let rhsRaw = rhs.asSmall._storage
33+
34+
if lhsRaw.0 != rhsRaw.0 {
35+
return _lexicographicalCompare(
36+
lhsRaw.0.byteSwapped, rhsRaw.0.byteSwapped, expecting: expecting)
37+
}
38+
return _lexicographicalCompare(
39+
lhsRaw.1.byteSwapped, rhsRaw.1.byteSwapped, expecting: expecting)
40+
}
41+
2142
return _stringCompareInternal(lhs, rhs, expecting: expecting)
2243
}
2344

45+
@inline(never) // Keep `_stringCompareWithSmolCheck` fast-path fast
2446
@usableFromInline
2547
@_effects(readonly)
2648
internal func _stringCompareInternal(

stdlib/public/core/StringCreate.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,5 +169,16 @@ extension String {
169169
) -> String {
170170
return String._fromCodeUnits(utf16, encoding: UTF16.self, repair: true)!.0
171171
}
172+
173+
@usableFromInline
174+
internal static func _fromSubstring(
175+
_ substring: __shared Substring
176+
) -> String {
177+
if substring._offsetRange == substring._wholeString._offsetRange {
178+
return substring._wholeString
179+
}
180+
181+
return substring._withUTF8 { return String._uncheckedFromUTF8($0) }
182+
}
172183
}
173184

stdlib/public/core/StringGuts.swift

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ extension _StringGuts {
9090
@inline(__always) get { return _object.isSmall }
9191
}
9292

93+
internal var isSmallASCII: Bool {
94+
@inline(__always) get { return _object.isSmall && _object.smallIsASCII }
95+
}
96+
9397
@inlinable
9498
internal var asSmall: _SmallString {
9599
@inline(__always) get { return _SmallString(_object) }

stdlib/public/core/Substring.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ extension String {
2020
/// - Complexity: O(*n*), where *n* is the length of `substring`.
2121
@inlinable
2222
public init(_ substring: __shared Substring) {
23-
self = substring._withUTF8 { return String._uncheckedFromUTF8($0) }
23+
self = String._fromSubstring(substring)
2424
}
2525
}
2626

0 commit comments

Comments
 (0)