//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See http://swift.org/LICENSE.txt for license information // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// %{ from SwiftIntTypes import all_integer_types, int_max_bits # Number of bits in the Builtin.Word type word_bits = int(CMAKE_SIZEOF_VOID_P) * 8 }% //===--- Parsing helpers --------------------------------------------------===// /// If text is an ASCII representation in the given `radix` of a /// non-negative number <= `maximum`, return that number. Otherwise, /// return `nil`. /// /// - Note: If `text` begins with `"+"` or `"-"`, even if the rest of /// the characters are `"0"`, the result is `nil`. // FIXME(integers): support a more general BinaryInteger protocol internal func _parseUnsignedAsciiAsUInt64( _ u16: String.UTF16View, _ radix: Int, _ maximum: UInt64 ) -> UInt64? { if u16.isEmpty { return nil } let digit = _ascii16("0")..._ascii16("9") let lower = _ascii16("a")..._ascii16("z") let upper = _ascii16("A")..._ascii16("Z") _precondition(radix > 1, "Radix must be greater than 1") _precondition( radix <= numericCast(10 + lower.count), "Radix exceeds what can be expressed using the English alphabet") let uRadix = UInt64(bitPattern: Int64(radix)) var result: UInt64 = 0 for c in u16 { let n: UInt64 switch c { case digit: n = UInt64(c - digit.lowerBound) case lower: n = UInt64(c - lower.lowerBound) + 10 case upper: n = UInt64(c - upper.lowerBound) + 10 default: return nil } if n >= uRadix { return nil } let (result1, overflow1) = result.multipliedWithOverflow(by: uRadix) let (result2, overflow2) = result1.addingWithOverflow(n) result = result2 if overflow1 != .none || overflow2 != .none || result > maximum { return nil } } return result } /// If text is an ASCII representation in the given `radix` of a /// non-negative number <= `maximum`, return that number. Otherwise, /// return `nil`. /// /// - Note: For text matching the regular expression "-0+", the result /// is `0`, not `nil`. // FIXME(integers): support a more general BinaryInteger protocol internal func _parseAsciiAsUInt64( _ utf16: String.UTF16View, _ radix: Int, _ maximum: UInt64 ) -> UInt64? { if utf16.isEmpty { return nil } // Parse (optional) sign. let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16) // Parse digits. guard let result = _parseUnsignedAsciiAsUInt64(digitsUTF16, radix, maximum) else { return nil } // Disallow < 0. if hasMinus && result != 0 { return nil } return result } /// If text is an ASCII representation in the given `radix` of a /// number >= -`maximum` - 1 and <= `maximum`, return that number. /// Otherwise, return `nil`. /// /// - Note: For text matching the regular expression "-0+", the result /// is `0`, not `nil`. // FIXME(integers): support a more general BinaryInteger protocol internal func _parseAsciiAsInt64( _ utf16: String.UTF16View, _ radix: Int, _ maximum: Int64 ) -> Int64? { _sanityCheck(maximum >= 0, "maximum should be non-negative") if utf16.isEmpty { return nil } // Parse (optional) sign. let (digitsUTF16, hasMinus) = _parseOptionalAsciiSign(utf16) // Parse digits. +1 for negatives because e.g. Int8's range is -128...127. let absValueMax = UInt64(bitPattern: maximum) + (hasMinus ? 1 : 0) guard let absValue = _parseUnsignedAsciiAsUInt64(digitsUTF16, radix, absValueMax) else { return nil } // Convert to signed. return Int64(bitPattern: hasMinus ? 0 &- absValue : absValue) } /// Strip an optional single leading ASCII plus/minus sign from `utf16`. private func _parseOptionalAsciiSign( _ utf16: String.UTF16View ) -> (digitsUTF16: String.UTF16View, isMinus: Bool) { switch utf16.first { case _ascii16("-")?: return (utf16.dropFirst(), true) case _ascii16("+")?: return (utf16.dropFirst(), false) default: return (utf16, false) } } //===--- Loop over all integer types --------------------------------------===// % for self_ty in all_integer_types(word_bits): % signed = self_ty.is_signed % Self = self_ty.stdlib_name extension ${Self} { /// Construct from an ASCII representation in the given `radix`. /// /// If `text` does not match the regular expression /// "[+-]?[0-9a-zA-Z]+", or the value it denotes in the given `radix` /// is not representable, the result is `nil`. public init?(_ text: String, radix: Int = 10) { if let value = _parseAsciiAs${'' if signed else 'U'}Int${int_max_bits}( text.utf16, radix, ${'' if signed else 'U'}Int${int_max_bits}(${Self}.max)) { self.init( ${'' if Self in ('Int64', 'UInt64') else 'truncatingBitPattern:'} value) } else { return nil } } } % end