//===----------------------------------------------------------------------===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// import SwiftShims extension String { /// Creates a new string representing the given string repeated the specified /// number of times. /// /// For example, you can use this initializer to create a string with ten /// `"ab"` strings in a row. /// /// let s = String(repeating: "ab", count: 10) /// print(s) /// // Prints "abababababababababab" /// /// - Parameters: /// - repeatedValue: The string to repeat. /// - count: The number of times to repeat `repeatedValue` in the resulting /// string. @_inlineable // FIXME(sil-serialize-all) public init(repeating repeatedValue: String, count: Int) { if count == 0 { self = "" return } precondition(count > 0, "Negative count not allowed") let s = repeatedValue self = String(_storage: _StringBuffer( capacity: s._core.count * count, initialSize: 0, elementWidth: s._core.elementWidth)) for _ in 0.. Bool @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) @_silgen_name("swift_stdlib_NSStringHasPrefixNFDPointer") internal func _stdlib_NSStringHasPrefixNFDPointer( _ theString: OpaquePointer, _ prefix: OpaquePointer) -> Bool /// Determines if `theString` ends with `suffix` comparing the strings under /// canonical equivalence. @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) @_silgen_name("swift_stdlib_NSStringHasSuffixNFD") internal func _stdlib_NSStringHasSuffixNFD( _ theString: AnyObject, _ suffix: AnyObject) -> Bool @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) @_silgen_name("swift_stdlib_NSStringHasSuffixNFDPointer") internal func _stdlib_NSStringHasSuffixNFDPointer( _ theString: OpaquePointer, _ suffix: OpaquePointer) -> Bool extension String { /// Returns a Boolean value indicating whether the string begins with the /// specified prefix. /// /// The comparison is both case sensitive and Unicode safe. The /// case-sensitive comparison will only match strings whose corresponding /// characters have the same case. /// /// let cafe = "Café du Monde" /// /// // Case sensitive /// print(cafe.hasPrefix("café")) /// // Prints "false" /// /// The Unicode-safe comparison matches Unicode scalar values rather than the /// code points used to compose them. The example below uses two strings /// with different forms of the `"é"` character---the first uses the composed /// form and the second uses the decomposed form. /// /// // Unicode safe /// let composedCafe = "Café" /// let decomposedCafe = "Cafe\u{0301}" /// /// print(cafe.hasPrefix(composedCafe)) /// // Prints "true" /// print(cafe.hasPrefix(decomposedCafe)) /// // Prints "true" /// /// - Parameter prefix: A possible prefix to test against this string. /// - Returns: `true` if the string begins with `prefix`; otherwise, `false`. @_inlineable // FIXME(sil-serialize-all) public func hasPrefix(_ prefix: String) -> Bool { let selfCore = self._core let prefixCore = prefix._core let prefixCount = prefixCore.count if prefixCount == 0 { return true } if let selfASCIIBuffer = selfCore.asciiBuffer, let prefixASCIIBuffer = prefixCore.asciiBuffer { if prefixASCIIBuffer.count > selfASCIIBuffer.count { // Prefix is longer than self. return false } return _stdlib_memcmp( selfASCIIBuffer.baseAddress!, prefixASCIIBuffer.baseAddress!, prefixASCIIBuffer.count) == (0 as CInt) } if selfCore.hasContiguousStorage && prefixCore.hasContiguousStorage { let lhsStr = _NSContiguousString(selfCore) let rhsStr = _NSContiguousString(prefixCore) return lhsStr._unsafeWithNotEscapedSelfPointerPair(rhsStr) { return _stdlib_NSStringHasPrefixNFDPointer($0, $1) } } return _stdlib_NSStringHasPrefixNFD( self._bridgeToObjectiveCImpl(), prefix._bridgeToObjectiveCImpl()) } /// Returns a Boolean value indicating whether the string ends with the /// specified suffix. /// /// The comparison is both case sensitive and Unicode safe. The /// case-sensitive comparison will only match strings whose corresponding /// characters have the same case. /// /// let plans = "Let's meet at the café" /// /// // Case sensitive /// print(plans.hasSuffix("Café")) /// // Prints "false" /// /// The Unicode-safe comparison matches Unicode scalar values rather than the /// code points used to compose them. The example below uses two strings /// with different forms of the `"é"` character---the first uses the composed /// form and the second uses the decomposed form. /// /// // Unicode safe /// let composedCafe = "café" /// let decomposedCafe = "cafe\u{0301}" /// /// print(plans.hasSuffix(composedCafe)) /// // Prints "true" /// print(plans.hasSuffix(decomposedCafe)) /// // Prints "true" /// /// - Parameter suffix: A possible suffix to test against this string. /// - Returns: `true` if the string ends with `suffix`; otherwise, `false`. @_inlineable // FIXME(sil-serialize-all) public func hasSuffix(_ suffix: String) -> Bool { let selfCore = self._core let suffixCore = suffix._core let suffixCount = suffixCore.count if suffixCount == 0 { return true } if let selfASCIIBuffer = selfCore.asciiBuffer, let suffixASCIIBuffer = suffixCore.asciiBuffer { if suffixASCIIBuffer.count > selfASCIIBuffer.count { // Suffix is longer than self. return false } return _stdlib_memcmp( selfASCIIBuffer.baseAddress! + (selfASCIIBuffer.count - suffixASCIIBuffer.count), suffixASCIIBuffer.baseAddress!, suffixASCIIBuffer.count) == (0 as CInt) } if selfCore.hasContiguousStorage && suffixCore.hasContiguousStorage { let lhsStr = _NSContiguousString(selfCore) let rhsStr = _NSContiguousString(suffixCore) return lhsStr._unsafeWithNotEscapedSelfPointerPair(rhsStr) { return _stdlib_NSStringHasSuffixNFDPointer($0, $1) } } return _stdlib_NSStringHasSuffixNFD( self._bridgeToObjectiveCImpl(), suffix._bridgeToObjectiveCImpl()) } } #else // FIXME: Implement hasPrefix and hasSuffix without objc // rdar://problem/18878343 #endif @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) internal func _ascii8(_ c: Unicode.Scalar) -> UInt8 { _sanityCheck(c.value >= 0 && c.value <= 0x7F, "not ASCII") return UInt8(c.value) } @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) internal func _digitASCII( _ digit: UInt8, numeralsOnly: Bool, uppercase: Bool ) -> UInt8 { if numeralsOnly || digit < 10 { return _ascii8("0") &+ digit } else { let base = (uppercase ? _ascii8("A") : _ascii8("a")) &- 10 return base &+ digit } } @_inlineable // FIXME(sil-serialize-all) @_versioned // FIXME(sil-serialize-all) internal func _integerToString( _ value: T, radix: Int, uppercase: Bool ) -> String { if value == 0 { return "0" } // Bit shifting / masking is much faster than division when `radix` // is a power of two. let radixIsPowerOfTwo = radix.nonzeroBitCount == 1 let radix = T.Magnitude(radix) let quotientAndRemainder: (T.Magnitude) -> (T.Magnitude, T.Magnitude) = radixIsPowerOfTwo ? { ( $0 &>> radix.trailingZeroBitCount, $0 & (radix - 1) ) } : { $0.quotientAndRemainder(dividingBy: radix) } let isNegative = T.isSigned && value < 0 var value = value.magnitude var result: [UInt8] = [] while value != 0 { let (q, r) = quotientAndRemainder(value) result.append( _digitASCII( UInt8(truncatingIfNeeded: r), numeralsOnly: radix <= 10, uppercase: uppercase)) value = q } if isNegative { result.append(_ascii8("-")) } return String._fromWellFormedCodeUnitSequence( UTF8.self, input: result.reversed()) } // Conversions to string from other types. extension String { /// Creates a string representing the given value in base 10, or some other /// specified base. /// /// The following example converts the maximal `Int` value to a string and /// prints its length: /// /// let max = String(Int.max) /// print("\(max) has \(max.count) digits.") /// // Prints "9223372036854775807 has 19 digits." /// /// Numerals greater than 9 are represented as Roman letters. These letters /// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`. /// /// let v = 999_999 /// print(String(v, radix: 2)) /// // Prints "11110100001000111111" /// /// print(String(v, radix: 16)) /// // Prints "f423f" /// print(String(v, radix: 16, uppercase: true)) /// // Prints "F423F" /// /// - Parameters: /// - value: The value to convert to a string. /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. /// - uppercase: Pass `true` to use uppercase letters to represent numerals /// greater than 9, or `false` to use lowercase letters. The default is /// `false`. // FIXME(integers): support a more general BinaryInteger protocol // FIXME(integers): support larger bitwidths than 64 @_inlineable // FIXME(sil-serialize-all) public init( _ value: T, radix: Int = 10, uppercase: Bool = false ) { _precondition(2...36 ~= radix, "Radix must be between 2 and 36") if T.bitWidth <= 64 { self = _int64ToString( Int64(value), radix: Int64(radix), uppercase: uppercase) } else { self = _integerToString(value, radix: radix, uppercase: uppercase) } } /// Creates a string representing the given value in base 10, or some other /// specified base. /// /// The following example converts the maximal `Int` value to a string and /// prints its length: /// /// let max = String(Int.max) /// print("\(max) has \(max.count) digits.") /// // Prints "9223372036854775807 has 19 digits." /// /// Numerals greater than 9 are represented as Roman letters. These letters /// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`. /// /// let v = 999_999 /// print(String(v, radix: 2)) /// // Prints "11110100001000111111" /// /// print(String(v, radix: 16)) /// // Prints "f423f" /// print(String(v, radix: 16, uppercase: true)) /// // Prints "F423F" /// /// - Parameters: /// - value: The value to convert to a string. /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. /// - uppercase: Pass `true` to use uppercase letters to represent numerals /// greater than 9, or `false` to use lowercase letters. The default is /// `false`. // FIXME(integers): tiebreaker between T : FixedWidthInteger and other obsoleted @_inlineable // FIXME(sil-serialize-all) @available(swift, obsoleted: 4) public init( _ value: T, radix: Int = 10, uppercase: Bool = false ) where T : SignedInteger { _precondition(2...36 ~= radix, "Radix must be between 2 and 36") if T.bitWidth <= 64 { self = _int64ToString( Int64(value), radix: Int64(radix), uppercase: uppercase) } else { self = _integerToString(value, radix: radix, uppercase: uppercase) } } /// Creates a string representing the given value in base 10, or some other /// specified base. /// /// The following example converts the maximal `Int` value to a string and /// prints its length: /// /// let max = String(Int.max) /// print("\(max) has \(max.count) digits.") /// // Prints "9223372036854775807 has 19 digits." /// /// Numerals greater than 9 are represented as Roman letters. These letters /// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`. /// /// let v: UInt = 999_999 /// print(String(v, radix: 2)) /// // Prints "11110100001000111111" /// /// print(String(v, radix: 16)) /// // Prints "f423f" /// print(String(v, radix: 16, uppercase: true)) /// // Prints "F423F" /// /// - Parameters: /// - value: The value to convert to a string. /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. /// - uppercase: Pass `true` to use uppercase letters to represent numerals /// greater than 9, or `false` to use lowercase letters. The default is /// `false`. // FIXME(integers): support a more general BinaryInteger protocol @_inlineable // FIXME(sil-serialize-all) public init( _ value: T, radix: Int = 10, uppercase: Bool = false ) where T : UnsignedInteger { _precondition(2...36 ~= radix, "Radix must be between 2 and 36") if T.bitWidth <= 64 { self = _uint64ToString( UInt64(value), radix: Int64(radix), uppercase: uppercase) } else { self = _integerToString(value, radix: radix, uppercase: uppercase) } } /// Creates a string representing the given value in base 10, or some other /// specified base. /// /// The following example converts the maximal `Int` value to a string and /// prints its length: /// /// let max = String(Int.max) /// print("\(max) has \(max.count) digits.") /// // Prints "9223372036854775807 has 19 digits." /// /// Numerals greater than 9 are represented as Roman letters. These letters /// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`. /// /// let v = 999_999 /// print(String(v, radix: 2)) /// // Prints "11110100001000111111" /// /// print(String(v, radix: 16)) /// // Prints "f423f" /// print(String(v, radix: 16, uppercase: true)) /// // Prints "F423F" /// /// - Parameters: /// - value: The value to convert to a string. /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. /// - uppercase: Pass `true` to use uppercase letters to represent numerals /// greater than 9, or `false` to use lowercase letters. The default is /// `false`. @_inlineable // FIXME(sil-serialize-all) @available(swift, obsoleted: 4, message: "Please use the version for FixedWidthInteger instead.") public init( _ value: T, radix: Int = 10, uppercase: Bool = false ) { _precondition(2...36 ~= radix, "Radix must be between 2 and 36") self = _int64ToString( Int64(value), radix: Int64(radix), uppercase: uppercase) } /// Creates a string representing the given value in base 10, or some other /// specified base. /// /// The following example converts the maximal `Int` value to a string and /// prints its length: /// /// let max = String(Int.max) /// print("\(max) has \(max.count) digits.") /// // Prints "9223372036854775807 has 19 digits." /// /// Numerals greater than 9 are represented as Roman letters. These letters /// start with `"A"` if `uppercase` is `true`; otherwise, with `"a"`. /// /// let v: UInt = 999_999 /// print(String(v, radix: 2)) /// // Prints "11110100001000111111" /// /// print(String(v, radix: 16)) /// // Prints "f423f" /// print(String(v, radix: 16, uppercase: true)) /// // Prints "F423F" /// /// - Parameters: /// - value: The value to convert to a string. /// - radix: The base to use for the string representation. `radix` must be /// at least 2 and at most 36. The default is 10. /// - uppercase: Pass `true` to use uppercase letters to represent numerals /// greater than 9, or `false` to use lowercase letters. The default is /// `false`. @_inlineable // FIXME(sil-serialize-all) @available(swift, obsoleted: 4, message: "Please use the version for FixedWidthInteger instead.") public init( _ value: T, radix: Int = 10, uppercase: Bool = false ) { _precondition(2...36 ~= radix, "Radix must be between 2 and 36") self = _uint64ToString( UInt64(value), radix: Int64(radix), uppercase: uppercase) } }