Skip to content

Commit 246d52d

Browse files
authored
Simplify the floating-point parsing initializers (#28992)
The original version scanned the entire input string for whitespace and non-ASCII characters. Both are unnecessary: the C routines we're building on already stop at non-ASCII characters or non-leading whitespace. So we need only check the first character for whitespace and verify that all characters are consumed. This both improves performance and reduces the amount of code that gets inlined into consumers.
1 parent b7e08ac commit 246d52d

File tree

1 file changed

+24
-11
lines changed

1 file changed

+24
-11
lines changed

stdlib/public/core/FloatingPointParsing.swift.gyb

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -126,25 +126,38 @@ extension ${Self}: LosslessStringConvertible {
126126
/// is `nil`.
127127
@inlinable // FIXME(sil-serialize-all)
128128
public init?<S: StringProtocol>(_ text: S) {
129-
let u8 = text.utf8
130-
131-
let (result, n): (${Self}, Int) = text.withCString { chars in
129+
let result: ${Self}? = text.withCString { chars in
130+
// TODO: We should change the ABI for
131+
// _swift_stdlib_strtoX_clocale so that it returns
132+
// a boolean `false` for leading whitespace, empty
133+
// string, or invalid character. Then we could avoid
134+
// inlining these checks into every single client.
135+
switch chars[0] {
136+
case 9, 10, 11, 12, 13, 32:
137+
// Reject any input with leading whitespace.
138+
return nil
139+
case 0:
140+
// Reject the empty string
141+
return nil
142+
default:
143+
break
144+
}
132145
var result: ${Self} = 0
133146
let endPtr = withUnsafeMutablePointer(to: &result) {
134147
_swift_stdlib_strto${cFuncSuffix2[bits]}_clocale(chars, $0)
135148
}
136-
return (result, endPtr == nil ? 0 : endPtr! - chars)
149+
// Verify that all the characters were consumed.
150+
if endPtr == nil || endPtr![0] != 0 {
151+
return nil
152+
}
153+
return result
137154
}
138155

139-
if n == 0 || n != u8.count
140-
|| u8.contains(where: { codeUnit in
141-
// Check if the code unit is either non-ASCII or if isspace(codeUnit)
142-
// would return nonzero when the current locale is the C locale.
143-
codeUnit > 127 || "\t\n\u{b}\u{c}\r ".utf8.contains(codeUnit)
144-
}) {
156+
if let result = result {
157+
self = result
158+
} else {
145159
return nil
146160
}
147-
self = result
148161
}
149162
}
150163

0 commit comments

Comments
 (0)