@@ -67,21 +67,21 @@ internal func _parseUnsignedAsciiAsUIntMax(
67
67
/// non-negative number <= `maximum`, return that number. Otherwise,
68
68
/// return `nil`.
69
69
///
70
- /// - Note: If ` text` begins with `"+"` or `"-"`, even if the rest of
71
- /// the characters are `"0" `, the result is `nil`.
70
+ /// - Note: For text matching the regular expression "-0+", the result
71
+ /// is `0 `, not `nil`.
72
72
internal func _parseAsciiAsUIntMax(
73
- u16 : String.UTF16View, _ radix: Int, _ maximum: UIntMax
73
+ utf16 : String.UTF16View, _ radix: Int, _ maximum: UIntMax
74
74
) -> UIntMax? {
75
- if u16 .isEmpty { return nil }
76
- let c = u16.first
77
- if _fastPath(c != _ascii16("-")) {
78
- let unsignedText
79
- = c == _ascii16("+") ? u16.dropFirst() : u16
80
- return _parseUnsignedAsciiAsUIntMax(unsignedText, radix, maximum)
81
- }
82
- else {
83
- return _parseAsciiAsIntMax(u16, radix, 0) == 0 ? 0 : nil
84
- }
75
+ if utf16 .isEmpty { return nil }
76
+ // Parse (optional) sign.
77
+ let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16)
78
+ // Parse digits.
79
+ guard let result = _parseUnsignedAsciiAsUIntMax(digitsUTF16, radix, maximum)
80
+ else { return nil }
81
+ // Disallow < 0.
82
+ if hasMinus && result != 0 { return nil }
83
+ // Return.
84
+ return result
85
85
}
86
86
87
87
/// If text is an ASCII representation in the given `radix` of a
@@ -91,23 +91,30 @@ internal func _parseAsciiAsUIntMax(
91
91
/// - Note: For text matching the regular expression "-0+", the result
92
92
/// is `0`, not `nil`.
93
93
internal func _parseAsciiAsIntMax(
94
- u16 : String.UTF16View, _ radix: Int, _ maximum: IntMax
94
+ utf16 : String.UTF16View, _ radix: Int, _ maximum: IntMax
95
95
) -> IntMax? {
96
96
_sanityCheck(maximum >= 0, "maximum should be non-negative")
97
+ if utf16.isEmpty { return nil }
98
+ // Parse (optional) sign.
99
+ let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16)
100
+ // Parse digits. +1 for because e.g. Int8's range is -128...127.
101
+ let absValueMax = UIntMax(bitPattern: maximum) + (hasMinus ? 1 : 0)
102
+ guard let absValue =
103
+ _parseUnsignedAsciiAsUIntMax(digitsUTF16, radix, absValueMax)
104
+ else { return nil }
105
+ // Return signed result.
106
+ return IntMax(bitPattern: hasMinus ? 0 &- absValue : absValue)
107
+ }
97
108
98
- if u16.isEmpty { return nil }
99
-
100
- // Drop any leading "-"
101
- let negative = u16.first == _ascii16("-")
102
- let absResultText = negative ? u16.dropFirst() : u16
103
-
104
- let absResultMax = UIntMax(bitPattern: maximum) + (negative ? 1 : 0)
105
-
106
- // Parse the result as unsigned
107
- if let absResult = _parseAsciiAsUIntMax(absResultText, radix, absResultMax) {
108
- return IntMax(bitPattern: negative ? 0 &- absResult : absResult)
109
+ /// Strip an optional single leading ASCII plus/minus sign from `utf16`.
110
+ private func _parseOptionalAsciiSign(
111
+ utf16: String.UTF16View
112
+ ) -> (digitsUTF16: String.UTF16View, isMinus: Bool) {
113
+ switch utf16.first {
114
+ case _ascii16("-")?: return (utf16.dropFirst(), true)
115
+ case _ascii16("+")?: return (utf16.dropFirst(), false)
116
+ default: return (utf16, false)
109
117
}
110
- return nil
111
118
}
112
119
113
120
//===--- Loop over all integer types --------------------------------------===//
0 commit comments