99// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
1010//
1111//===----------------------------------------------------------------------===//
12+ //
13+ // This defines the public APIs for parsing floating point numbers.
14+ //
15+ // The backing implementation is in `FloatingPointFromString.swift`
16+ //
17+ //===----------------------------------------------------------------------===//
18+
1219
1320import SwiftShims
1421
@@ -122,6 +129,10 @@ extension ${Self}: LosslessStringConvertible {
122129 /// // p?.isNaN == true
123130 /// // String(p!) == "nan(0x10)"
124131 ///
132+ /// - An input string of `"snan"` (case insensitive) is converted
133+ /// into a *signaling NaN* value. This form permits an optional
134+ /// payload in the same format as for a non-signaling NaN.
135+ ///
125136 /// A string in any other format than those described above
126137 /// or containing additional characters
127138 /// results in a `nil` value. For example, the following conversions
@@ -134,7 +145,7 @@ extension ${Self}: LosslessStringConvertible {
134145 /// A decimal or hexadecimal string is converted to a `${Self}`
135146 /// instance using the IEEE 754 roundTiesToEven (default) rounding
136147 /// attribute.
137- /// Values with absolute value smaller than `${Self}.leastNonzeroMagnitude`
148+ /// Values with absolute value smaller than one-half of `${Self}.leastNonzeroMagnitude`
138149 /// are rounded to plus or minus zero.
139150 /// Values with absolute value larger than `${Self}.greatestFiniteMagnitude`
140151 /// are rounded to plus or minus infinity.
@@ -161,13 +172,26 @@ extension ${Self}: LosslessStringConvertible {
161172 /// - Parameter text: An input string to convert to a `${Self}?` instance.
162173 ///
163174 @inlinable
175+ // This is inlinable because the unspecialized generic takes a protocol
176+ // argument; inlining might be able to specialize away the existential.
164177 public init?< S : StringProtocol> ( _ text: S) {
165178 % if bits == 16 :
179+ // Float16 has only been supported since Swift 5.3, so it can
180+ // unconditionally delegate to init(_:Substring)
166181 self . init ( Substring ( text) )
167182 % else:
168- if #available(macOS 11.0, iOS 14.0, watchOS 7.0, tvOS 14.0, *) { //SwiftStdlib 5.3
183+ if #available( macOS 11 . 0 , iOS 14 . 0 , watchOS 7 . 0 , tvOS 14 . 0 , * ) {
184+ // On SwiftStdlib 5.3 and later, we can just delegate to the
185+ // init(_:Substring) initializer:
169186 self . init ( Substring ( text) )
170187 } else {
188+ // When running on SwiftStdlib <5.3, we can't just delegate to
189+ // the init(_:Substring) initializer, so we have to inline the whole thing...
190+
191+ // This means we must preserve the _swift_stdlib_strto{f,d,ld}_clocale
192+ // ABI for as long as we support code compiled for Swift < 5.3, which
193+ // includes macOS < 11.0, iOS/tvOS < 14.0, or watchOS < 7.0
194+
171195 self = 0.0
172196 let success = unsafe _withUnprotectedUnsafeMutablePointer( to: & self ) { p -> Bool in
173197 unsafe text. withCString { chars -> Bool in
@@ -191,14 +215,77 @@ extension ${Self}: LosslessStringConvertible {
191215 % end
192216 }
193217
194- // Caveat: This implementation used to be inlineable.
195- // In particular, we still have to export
196- // _swift_stdlib_strtoXYZ_clocale()
197- // as ABI to support old compiled code that still requires it.
218+ % if bits in [ 16 , 32 , 64 ] :
219+
220+ // Various entry points that take concrete types. Note that these
221+ // are deliberately NOT inlinable:
222+ // * There is no performance advantage to inlining
223+ // * There is a code size disadvantage to inlining
224+ // * We don't want to use the `StringProtocol` API for these common cases as
225+ // that pessimizes either performance or code size depending on whether it
226+ // gets inlined.
227+
228+ // TODO: Expose a concrete `String` API to optimize the common case
229+ /*
230+ @available(SwiftStdlib 6.4, *)
231+ public init?(_ text: String) {
232+ if let d = parse_float(text.utf8.span) {
233+ self = d
234+ } else {
235+ return nil
236+ }
237+ }
238+ */
239+
240+ // TODO: Expose Span-taking API publicly
241+ // TODO: Some applications would like to restrict the patterns supported
242+ // here. We could do that by adding an option set here that indicates
243+ // the supported patterns, or we could expose additional entry points to
244+ // support common use cases (e.g., JSON).
245+ /*
246+ @available(SwiftStdlib 6.4, *)
247+ public init?(_ text: Span<UInt8>) {
248+ if let d = parse_float(text) {
249+ self = d
250+ } else {
251+ return nil
252+ }
253+ }
254+ */
255+
256+ // Use the all-Swift `parse_float${bits}()` implementation for Float16/32/64
257+ @available( SwiftStdlib 5.3 , * )
258+ public init? ( _ text: Substring) {
259+ // TODO: Someday, this whole function should simplify down to just:
260+ // ${Self}(text.utf8.span)
261+ #if _pointerBitWidth(_16)
262+ // Always fail on 16-bit targets
263+ return nil
264+ #else
265+ // Work around span availability limits
266+ let parsed = unsafe text. base . _guts . withFastUTF8 { chars -> ${ Self} ? in
267+ unsafe parse_float${ bits} ( chars. span)
268+ }
269+
270+ if let parsed {
271+ self = parsed
272+ } else {
273+ return nil
274+ }
275+ #endif
276+ }
277+
278+ % elif bits in [ 80 ] :
279+
280+ // For now, continue relying on libc-based implementation for Float80 support
281+ // TODO: Implement `parse_float80(_:Span)` so this can
282+ // be implemented the same as above.
198283 @available( SwiftStdlib 5.3 , * )
199284 public init? ( _ text: Substring) {
200285 self = 0.0
201286 let success = unsafe _withUnprotectedUnsafeMutablePointer( to: & self ) { p -> Bool in
287+ // Make a copy of `text` to ensure we have a null-terminated C string
288+ // to pass to the libc API:
202289 unsafe text. withCString { chars -> Bool in
203290 switch unsafe chars[ 0 ] {
204291 case 9 , 10 , 11 , 12 , 13 , 32 :
@@ -217,8 +304,10 @@ extension ${Self}: LosslessStringConvertible {
217304 return nil
218305 }
219306 }
307+ % end
220308}
221309
310+
222311% if bits in [ 16 , 80 ] :
223312#endif
224313% end
0 commit comments