Skip to content

Commit 4d0e2ad

Browse files
authored
Further refinement of {Float,Double,Float80}.init(_:String) (swiftlang#29028)
* Further refinement of {Float,Double,Float80}.init(_:String) After talking with @stephentyrone, I found some additional simplifications. No functional change, just shorter/simpler. This makes the generic inlineable part a small stub that delegates to the full non-inlined version. ABI compatibility: * We support the same generic init() as before * _swift_stdlib_strtoXYZ_clocale is still available to support old inlined code API addition: * We now have a public specialized form of init?(_: Substring) in addition to the generic init?<S:StringProtocol> form. * Add @available marker to new API * Support back-deployment to older OSes by inlining the full version
1 parent 2f263a9 commit 4d0e2ad

File tree

1 file changed

+44
-26
lines changed

1 file changed

+44
-26
lines changed

stdlib/public/core/FloatingPointParsing.swift.gyb

Lines changed: 44 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -124,38 +124,56 @@ extension ${Self}: LosslessStringConvertible {
124124
/// - Parameter text: The input string to convert to a `${Self}` instance. If
125125
/// `text` has invalid characters or is in an invalid format, the result
126126
/// is `nil`.
127-
@inlinable // FIXME(sil-serialize-all)
127+
@inlinable
128128
public init?<S: StringProtocol>(_ text: S) {
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-
}
145-
var result: ${Self} = 0
146-
let endPtr = withUnsafeMutablePointer(to: &result) {
147-
_swift_stdlib_strto${cFuncSuffix2[bits]}_clocale(chars, $0)
129+
if #available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *) {
130+
self.init(Substring(text))
131+
} else {
132+
self = 0.0
133+
let success = withUnsafeMutablePointer(to: &self) { p -> Bool in
134+
text.withCString { chars -> Bool in
135+
switch chars[0] {
136+
case 9, 10, 11, 12, 13, 32:
137+
return false // Reject leading whitespace
138+
case 0:
139+
return false // Reject empty string
140+
default:
141+
break
142+
}
143+
let endPtr = _swift_stdlib_strto${cFuncSuffix2[bits]}_clocale(chars, p)
144+
// Succeed only if endPtr points to end of C string
145+
return endPtr != nil && endPtr![0] == 0
146+
}
148147
}
149-
// Verify that all the characters were consumed.
150-
if endPtr == nil || endPtr![0] != 0 {
148+
if !success {
151149
return nil
152150
}
153-
return result
154151
}
152+
}
155153

156-
if let result = result {
157-
self = result
158-
} else {
154+
// Caveat: This implementation used to be inlineable.
155+
// In particular, we still have to export
156+
// _swift_stdlib_strtoXYZ_clocale()
157+
// as ABI to support old compiled code that still requires it.
158+
@available(macOS 9999, iOS 9999, tvOS 9999, watchOS 9999, *)
159+
public init?(_ text: Substring) {
160+
self = 0.0
161+
let success = withUnsafeMutablePointer(to: &self) { p -> Bool in
162+
text.withCString { chars -> Bool in
163+
switch chars[0] {
164+
case 9, 10, 11, 12, 13, 32:
165+
return false // Reject leading whitespace
166+
case 0:
167+
return false // Reject empty string
168+
default:
169+
break
170+
}
171+
let endPtr = _swift_stdlib_strto${cFuncSuffix2[bits]}_clocale(chars, p)
172+
// Succeed only if endPtr points to end of C string
173+
return endPtr != nil && endPtr![0] == 0
174+
}
175+
}
176+
if !success {
159177
return nil
160178
}
161179
}

0 commit comments

Comments
 (0)