Skip to content

Commit c40c904

Browse files
committed
[stdlib] Address reviewer comments and make some minor edits to string-to-integer parsing.
1 parent 5d943f4 commit c40c904

File tree

1 file changed

+45
-38
lines changed

1 file changed

+45
-38
lines changed

stdlib/public/core/IntegerParsing.swift

Lines changed: 45 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,47 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
@_alwaysEmitIntoClient
14-
internal func _parseASCIIDigits<Result: FixedWidthInteger>(
14+
internal func _parseDigitsInASCII<Result: FixedWidthInteger>(
1515
_ codeUnits: UnsafeBufferPointer<UInt8>, radix: Int, isNegative: Bool
1616
) -> Result? {
1717
_internalInvariant(radix >= 2 && radix <= 36)
1818
guard _fastPath(!codeUnits.isEmpty) else { return nil }
19-
let numericalUpperBound, uppercaseUpperBound, lowercaseUpperBound: UInt8
19+
20+
// ASCII constants, named for clarity:
21+
let _0 = 48 as UInt8, _A = 65 as UInt8, _a = 97 as UInt8
22+
23+
let numericalUpperBound: UInt8
24+
let uppercaseUpperBound: UInt8
25+
let lowercaseUpperBound: UInt8
2026
if radix <= 10 {
21-
numericalUpperBound = 48 /* "0" */ &+ UInt8(radix)
22-
uppercaseUpperBound = 65
23-
lowercaseUpperBound = 97
27+
numericalUpperBound = _0 &+ UInt8(truncatingIfNeeded: radix)
28+
uppercaseUpperBound = _A
29+
lowercaseUpperBound = _a
2430
} else {
25-
numericalUpperBound = 58
26-
uppercaseUpperBound = 65 /* "A" */ &+ UInt8(radix &- 10)
27-
lowercaseUpperBound = 97 /* "a" */ &+ UInt8(radix &- 10)
31+
numericalUpperBound = _0 &+ 10
32+
uppercaseUpperBound = _A &+ UInt8(truncatingIfNeeded: radix &- 10)
33+
lowercaseUpperBound = _a &+ UInt8(truncatingIfNeeded: radix &- 10)
2834
}
29-
let multiplicand = Result(radix)
35+
let multiplicand = Result(truncatingIfNeeded: radix)
3036
var result = 0 as Result
3137
for digit in codeUnits {
3238
let digitValue: Result
33-
if _fastPath(digit >= 48 && digit < numericalUpperBound) {
34-
digitValue = Result(digit &- 48)
35-
} else if _fastPath(digit >= 65 && digit < uppercaseUpperBound) {
36-
digitValue = Result(digit &- 65 &+ 10)
37-
} else if _fastPath(digit >= 97 && digit < lowercaseUpperBound) {
38-
digitValue = Result(digit &- 97 &+ 10)
39+
if _fastPath(digit >= _0 && digit < numericalUpperBound) {
40+
digitValue = Result(truncatingIfNeeded: digit &- _0)
41+
} else if _fastPath(digit >= _A && digit < uppercaseUpperBound) {
42+
digitValue = Result(truncatingIfNeeded: digit &- _A &+ 10)
43+
} else if _fastPath(digit >= _a && digit < lowercaseUpperBound) {
44+
digitValue = Result(truncatingIfNeeded: digit &- _a &+ 10)
3945
} else {
4046
return nil
4147
}
42-
let (temporary, overflow1) =
43-
result.multipliedReportingOverflow(by: multiplicand)
44-
guard _fastPath(!overflow1) else { return nil }
45-
let (nextResult, overflow2) = isNegative
46-
? temporary.subtractingReportingOverflow(digitValue)
47-
: temporary.addingReportingOverflow(digitValue)
48-
guard _fastPath(!overflow2) else { return nil }
49-
result = nextResult
48+
let overflow1: Bool
49+
(result, overflow1) = result.multipliedReportingOverflow(by: multiplicand)
50+
let overflow2: Bool
51+
(result, overflow2) = isNegative
52+
? result.subtractingReportingOverflow(digitValue)
53+
: result.addingReportingOverflow(digitValue)
54+
guard _fastPath(!overflow1 && !overflow2) else { return nil }
5055
}
5156
return result
5257
}
@@ -56,18 +61,22 @@ internal func _parseASCII<Result: FixedWidthInteger>(
5661
_ codeUnits: UnsafeBufferPointer<UInt8>, radix: Int
5762
) -> Result? {
5863
_internalInvariant(!codeUnits.isEmpty)
64+
65+
// ASCII constants, named for clarity:
66+
let _plus = 43 as UInt8, _minus = 45 as UInt8
67+
5968
let first = codeUnits[0]
60-
if first == 45 /* "-" */ {
61-
return _parseASCIIDigits(
69+
if first == _minus {
70+
return _parseDigitsInASCII(
6271
UnsafeBufferPointer(rebasing: codeUnits[1...]),
6372
radix: radix, isNegative: true)
6473
}
65-
if first == 43 /* "+" */ {
66-
return _parseASCIIDigits(
74+
if first == _plus {
75+
return _parseDigitsInASCII(
6776
UnsafeBufferPointer(rebasing: codeUnits[1...]),
6877
radix: radix, isNegative: false)
6978
}
70-
return _parseASCIIDigits(codeUnits, radix: radix, isNegative: false)
79+
return _parseDigitsInASCII(codeUnits, radix: radix, isNegative: false)
7180
}
7281

7382
@_alwaysEmitIntoClient
@@ -150,18 +159,18 @@ extension FixedWidthInteger {
150159
}
151160
}
152161

153-
// -----------------------------------------------------------------------------
162+
//===----------------------------------------------------------------------===//
154163
// Old entry points preserved for ABI compatibility.
155-
// -----------------------------------------------------------------------------
164+
//===----------------------------------------------------------------------===//
156165

157166
/// Returns c as a UTF16.CodeUnit. Meant to be used as _ascii16("x").
158-
@usableFromInline
167+
@usableFromInline // Previously '@inlinable'.
159168
internal func _ascii16(_ c: Unicode.Scalar) -> UTF16.CodeUnit {
160169
_internalInvariant(c.value >= 0 && c.value <= 0x7F, "not ASCII")
161170
return UTF16.CodeUnit(c.value)
162171
}
163172

164-
@usableFromInline
173+
@usableFromInline // Previously '@inlinable @inline(__always)'.
165174
internal func _asciiDigit<CodeUnit: UnsignedInteger, Result: BinaryInteger>(
166175
codeUnit u_: CodeUnit, radix: Result
167176
) -> Result? {
@@ -179,7 +188,7 @@ internal func _asciiDigit<CodeUnit: UnsignedInteger, Result: BinaryInteger>(
179188
return Result(truncatingIfNeeded: d)
180189
}
181190

182-
@usableFromInline
191+
@usableFromInline // Previously '@inlinable @inline(__always)'.
183192
internal func _parseUnsignedASCII<
184193
Rest: IteratorProtocol, Result: FixedWidthInteger
185194
>(
@@ -209,12 +218,10 @@ where Rest.Element: UnsignedInteger {
209218
return result
210219
}
211220

212-
//
213-
// Before it was superseded, this function was about 20KB of always-inline code,
214-
// most of which were MOV instructions.
215-
//
221+
// This function has been superseded because it is about 20KB of previously
222+
// always-inline code, most of which are MOV instructions.
216223

217-
@usableFromInline
224+
@usableFromInline // Previously '@inlinable @inline(__always)'.
218225
internal func _parseASCII<
219226
CodeUnits: IteratorProtocol, Result: FixedWidthInteger
220227
>(

0 commit comments

Comments
 (0)