| //===----------------------------------------------------------------------===// |
| // |
| // 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 |
| // |
| //===----------------------------------------------------------------------===// |
| |
| extension String { |
| // FIXME(strings): at least temporarily remove it to see where it was applied |
| /// Creates a new string from the given substring. |
| /// |
| /// - Parameter substring: A substring to convert to a standalone `String` |
| /// instance. |
| /// |
| /// - Complexity: O(*n*), where *n* is the length of `substring`. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(_ substring: Substring) { |
| let x = substring._wholeString |
| let start = substring.startIndex |
| let end = substring.endIndex |
| let u16 = x._core[start.encodedOffset..<end.encodedOffset] |
| if start.samePosition(in: x.unicodeScalars) != nil |
| && end.samePosition(in: x.unicodeScalars) != nil { |
| self = String(_StringCore(u16)) |
| } |
| else { |
| self = String(decoding: u16, as: UTF16.self) |
| } |
| } |
| } |
| |
| /// A slice of a string. |
| /// |
| /// When you create a slice of a string, a `Substring` instance is the result. |
| /// Operating on substrings is fast and efficient because a substring shares |
| /// its storage with the original string. The `Substring` type presents the |
| /// same interface as `String`, so you can avoid or defer any copying of the |
| /// string's contents. |
| /// |
| /// The following example creates a `greeting` string, and then finds the |
| /// substring of the first sentence: |
| /// |
| /// let greeting = "Hi there! It's nice to meet you! 👋" |
| /// let endOfSentence = greeting.index(of: "!")! |
| /// let firstSentence = greeting[...endOfSentence] |
| /// // firstSentence == "Hi there!" |
| /// |
| /// You can perform many string operations on a substring. Here, we find the |
| /// length of the first sentence and create an uppercase version. |
| /// |
| /// print("'\(firstSentence)' is \(firstSentence.count) characters long.") |
| /// // Prints "'Hi there!' is 9 characters long." |
| /// |
| /// let shoutingSentence = firstSentence.uppercased() |
| /// // shoutingSentence == "HI THERE!" |
| /// |
| /// Converting a Substring to a String |
| /// ================================== |
| /// |
| /// This example defines a `rawData` string with some unstructured data, and |
| /// then uses the string's `prefix(while:)` method to create a substring of |
| /// the numeric prefix: |
| /// |
| /// let rawInput = "126 a.b 22219 zzzzzz" |
| /// let numericPrefix = rawInput.prefix(while: { "0"..."9" ~= $0 }) |
| /// // numericPrefix is the substring "126" |
| /// |
| /// When you need to store a substring or pass it to a function that requires a |
| /// `String` instance, convert it using the `String.init(_:)` initializer. |
| /// |
| /// _ = Int(numericPrefix, radix: 10) |
| /// // error: cannot convert value... |
| /// let prefix = Int(String(numericPrefix), radix: 10) |
| /// // prefix == 126 |
| /// |
| /// Calling this initializer copies the contents of the substring to a new |
| /// string. |
| /// |
| /// - Important: Don't store substrings longer than you need them to perform a |
| /// specific operation. A substring holds a reference to the entire storage |
| /// of the string it comes from, not just to the portion it presents, even |
| /// when there is no other reference to the original string. Storing |
| /// substrings may, therefore, prolong the lifetime of string data that is |
| /// no longer otherwise accessible, which can appear to be memory leakage. |
| @_fixed_layout // FIXME(sil-serialize-all) |
| public struct Substring : StringProtocol { |
| public typealias Index = String.Index |
| public typealias IndexDistance = String.IndexDistance |
| public typealias SubSequence = Substring |
| |
| @_versioned // FIXME(sil-serialize-all) |
| internal var _slice: Slice<String> |
| |
| /// Creates an empty substring. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init() { |
| _slice = Slice() |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal init(_slice: Slice<String>) { |
| self._slice = _slice |
| } |
| |
| /// Creates a substring with the specified bounds within the given string. |
| /// |
| /// - Parameters: |
| /// - base: The string to create a substring of. |
| /// - bounds: The range of `base` to use for the substring. The lower and |
| /// upper bounds of `bounds` must be valid indices of `base`. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(_base base: String, _ bounds: Range<Index>) { |
| _slice = Slice(base: base, bounds: bounds) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal init<R: RangeExpression>( |
| _base base: String, _ bounds: R |
| ) where R.Bound == Index { |
| self.init(_base: base, bounds.relative(to: base)) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public var startIndex: Index { return _slice.startIndex } |
| @_inlineable // FIXME(sil-serialize-all) |
| public var endIndex: Index { return _slice.endIndex } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index(after i: Index) -> Index { |
| _precondition(i < endIndex, "Cannot increment beyond endIndex") |
| _precondition(i >= startIndex, "Cannot increment an invalid index") |
| // FIXME(strings): slice types currently lack necessary bound checks |
| return _slice.index(after: i) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index(before i: Index) -> Index { |
| _precondition(i <= endIndex, "Cannot decrement an invalid index") |
| _precondition(i > startIndex, "Cannot decrement beyond startIndex") |
| // FIXME(strings): slice types currently lack necessary bound checks |
| return _slice.index(before: i) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index(_ i: Index, offsetBy n: IndexDistance) -> Index { |
| let result = _slice.index(i, offsetBy: n) |
| // FIXME(strings): slice types currently lack necessary bound checks |
| _precondition( |
| (_slice._startIndex ... _slice.endIndex).contains(result), |
| "Operation results in an invalid index") |
| return result |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index( |
| _ i: Index, offsetBy n: IndexDistance, limitedBy limit: Index |
| ) -> Index? { |
| let result = _slice.index(i, offsetBy: n, limitedBy: limit) |
| // FIXME(strings): slice types currently lack necessary bound checks |
| _precondition(result.map { |
| (_slice._startIndex ... _slice.endIndex).contains($0) |
| } ?? true, |
| "Operation results in an invalid index") |
| return result |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func distance(from start: Index, to end: Index) -> IndexDistance { |
| return _slice.distance(from: start, to: end) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public subscript(i: Index) -> Character { |
| return _slice[i] |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public mutating func replaceSubrange<C>( |
| _ bounds: Range<Index>, |
| with newElements: C |
| ) where C : Collection, C.Iterator.Element == Iterator.Element { |
| // FIXME(strings): slice types currently lack necessary bound checks |
| _slice.replaceSubrange(bounds, with: newElements) |
| } |
| |
| % for Range in ['Range', 'ClosedRange']: |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public mutating func replaceSubrange( |
| _ bounds: ${Range}<Index>, with newElements: Substring |
| ) { |
| replaceSubrange(bounds, with: newElements._slice) |
| } |
| |
| % end |
| |
| /// Creates a string from the given Unicode code units in the specified |
| /// encoding. |
| /// |
| /// - Parameters: |
| /// - codeUnits: A collection of code units encoded in the encoding |
| /// specified in `sourceEncoding`. |
| /// - sourceEncoding: The encoding in which `codeUnits` should be |
| /// interpreted. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init<C: Collection, Encoding: _UnicodeEncoding>( |
| decoding codeUnits: C, as sourceEncoding: Encoding.Type |
| ) where C.Iterator.Element == Encoding.CodeUnit { |
| self.init(String(decoding: codeUnits, as: sourceEncoding)) |
| } |
| |
| /// Creates a string from the null-terminated, UTF-8 encoded sequence of |
| /// bytes at the given pointer. |
| /// |
| /// - Parameter nullTerminatedUTF8: A pointer to a sequence of contiguous, |
| /// UTF-8 encoded bytes ending just before the first zero byte. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(cString nullTerminatedUTF8: UnsafePointer<CChar>) { |
| self.init(String(cString: nullTerminatedUTF8)) |
| } |
| |
| /// Creates a string from the null-terminated sequence of bytes at the given |
| /// pointer. |
| /// |
| /// - Parameters: |
| /// - nullTerminatedCodeUnits: A pointer to a sequence of contiguous code |
| /// units in the encoding specified in `sourceEncoding`, ending just |
| /// before the first zero code unit. |
| /// - sourceEncoding: The encoding in which the code units should be |
| /// interpreted. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init<Encoding: _UnicodeEncoding>( |
| decodingCString nullTerminatedCodeUnits: UnsafePointer<Encoding.CodeUnit>, |
| as sourceEncoding: Encoding.Type |
| ) { |
| self.init( |
| String(decodingCString: nullTerminatedCodeUnits, as: sourceEncoding)) |
| } |
| |
| /// Calls the given closure with a pointer to the contents of the string, |
| /// represented as a null-terminated sequence of UTF-8 code units. |
| /// |
| /// The pointer passed as an argument to `body` is valid only during the |
| /// execution of `withCString(_:)`. Do not store or return the pointer for |
| /// later use. |
| /// |
| /// - Parameter body: A closure with a pointer parameter that points to a |
| /// null-terminated sequence of UTF-8 code units. If `body` has a return |
| /// value, that value is also used as the return value for the |
| /// `withCString(_:)` method. The pointer argument is valid only for the |
| /// duration of the method's execution. |
| /// - Returns: The return value, if any, of the `body` closure parameter. |
| @_inlineable // FIXME(sil-serialize-all) |
| public func withCString<Result>( |
| _ body: (UnsafePointer<CChar>) throws -> Result) rethrows -> Result { |
| return try _wholeString._core._withCSubstringAndLength( |
| in: startIndex.encodedOffset..<endIndex.encodedOffset, |
| encoding: UTF8.self) { |
| p, length in try p.withMemoryRebound(to: CChar.self, capacity: length) { |
| try body($0) |
| } |
| } |
| } |
| |
| /// Calls the given closure with a pointer to the contents of the string, |
| /// represented as a null-terminated sequence of code units. |
| /// |
| /// The pointer passed as an argument to `body` is valid only during the |
| /// execution of `withCString(encodedAs:_:)`. Do not store or return the |
| /// pointer for later use. |
| /// |
| /// - Parameters: |
| /// - body: A closure with a pointer parameter that points to a |
| /// null-terminated sequence of code units. If `body` has a return |
| /// value, that value is also used as the return value for the |
| /// `withCString(encodedAs:_:)` method. The pointer argument is valid |
| /// only for the duration of the method's execution. |
| /// - targetEncoding: The encoding in which the code units should be |
| /// interpreted. |
| /// - Returns: The return value, if any, of the `body` closure parameter. |
| @_inlineable // FIXME(sil-serialize-all) |
| public func withCString<Result, TargetEncoding: _UnicodeEncoding>( |
| encodedAs targetEncoding: TargetEncoding.Type, |
| _ body: (UnsafePointer<TargetEncoding.CodeUnit>) throws -> Result |
| ) rethrows -> Result { |
| return try _wholeString._core._withCSubstring( |
| in: startIndex.encodedOffset..<endIndex.encodedOffset, |
| encoding: targetEncoding, body) |
| } |
| } |
| |
| extension Substring : _SwiftStringView { |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal var _persistentContent: String { |
| let wholeCore = _wholeString._core |
| let native = wholeCore.nativeBuffer |
| if _fastPath(native != nil) { |
| let wholeString = String(wholeCore) |
| let n = native._unsafelyUnwrappedUnchecked |
| if _fastPath( |
| n.start == wholeCore._baseAddress |
| && n.usedCount == wholeCore.count |
| && _slice.startIndex == wholeString.startIndex |
| && _slice.endIndex == wholeString.endIndex |
| ) { |
| return wholeString |
| } |
| } |
| var r = String() |
| r._core.append(_ephemeralContent._core) |
| _sanityCheck(r._core._owner !== _ephemeralContent._core._owner) |
| return r |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public // @testable |
| var _ephemeralContent: String { |
| let wholeCore = _wholeString._core |
| let subCore : _StringCore = wholeCore[ |
| startIndex.encodedOffset..<endIndex.encodedOffset] |
| // Check that we haven't allocated a new buffer for the result, if we have |
| // contiguous storage. |
| _sanityCheck( |
| subCore._owner === wholeCore._owner || !wholeCore.hasContiguousStorage) |
| |
| return String(subCore) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal |
| var _wholeString: String { |
| return _slice._base |
| } |
| } |
| |
| extension Substring : CustomReflectable { |
| @_inlineable // FIXME(sil-serialize-all) |
| public var customMirror: Mirror { |
| return String(self).customMirror |
| } |
| } |
| |
| extension Substring : CustomPlaygroundQuickLookable { |
| @_inlineable // FIXME(sil-serialize-all) |
| public var customPlaygroundQuickLook: PlaygroundQuickLook { |
| return String(self).customPlaygroundQuickLook |
| } |
| } |
| |
| extension Substring : CustomStringConvertible { |
| @_inlineable // FIXME(sil-serialize-all) |
| public var description: String { |
| return String(self) |
| } |
| } |
| |
| extension Substring : CustomDebugStringConvertible { |
| @_inlineable // FIXME(sil-serialize-all) |
| public var debugDescription: String { |
| return String(self).debugDescription |
| } |
| } |
| |
| extension Substring : LosslessStringConvertible { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(_ content: String) { |
| self.init(_base: content, content.startIndex ..< content.endIndex) |
| } |
| } |
| |
| extension StringProtocol { |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func ==<R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return lhs._ephemeralString == rhs._ephemeralString |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func !=<R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return lhs._ephemeralString != rhs._ephemeralString |
| } |
| } |
| |
| extension StringProtocol { |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func < <R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return lhs._ephemeralString < rhs._ephemeralString |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func > <R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return rhs < lhs |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func <= <R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return !(rhs < lhs) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public static func >= <R: StringProtocol>(lhs: Self, rhs: R) -> Bool { |
| return !(lhs < rhs) |
| } |
| } |
| |
| extension StringProtocol { |
| @_inlineable // FIXME(sil-serialize-all) |
| public var hashValue : Int { |
| return self._ephemeralString.hashValue |
| } |
| } |
| |
| % for (property, ViewPrefix) in [ |
| % ('utf8', 'UTF8'), |
| % ('utf16', 'UTF16'), |
| % ('unicodeScalars', 'UnicodeScalar'), |
| % ('characters', 'Character') |
| % ]: |
| % View = ViewPrefix + 'View' |
| % RangeReplaceable = 'RangeReplaceable' if property == 'unicodeScalars' else '' |
| extension Substring { |
| % if View == 'CharacterView': |
| @available(swift, deprecated: 3.2, message: |
| "Please use String or Substring directly") |
| % end |
| @_fixed_layout // FIXME(sil-serialize-all) |
| public struct ${View} { |
| @_versioned // FIXME(sil-serialize-all) |
| internal var _slice: Slice<String.${View}> |
| } |
| } |
| |
| extension Substring.${View} : BidirectionalCollection { |
| public typealias Index = String.Index |
| public typealias SubSequence = Substring.${View} |
| |
| /// Creates an instance that slices `base` at `_bounds`. |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal init(_ base: String.${View}, _bounds: Range<Index>) { |
| _slice = Slice( |
| base: String(base._core).${property}, |
| bounds: _bounds) |
| } |
| |
| /// The entire String onto whose slice this view is a projection. |
| @_inlineable // FIXME(sil-serialize-all) |
| @_versioned // FIXME(sil-serialize-all) |
| internal var _wholeString: String { |
| return String(_slice._base._core) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public var startIndex: Index { return _slice.startIndex } |
| @_inlineable // FIXME(sil-serialize-all) |
| public var endIndex: Index { return _slice.endIndex } |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index(after i: Index) -> Index { |
| return _slice.index(after: i) |
| } |
| @_inlineable // FIXME(sil-serialize-all) |
| public func index(before i: Index) -> Index { |
| return _slice.index(before: i) |
| } |
| @_inlineable // FIXME(sil-serialize-all) |
| public subscript(i: Index) -> String.${View}.Element { |
| return _slice[i] |
| } |
| @_inlineable // FIXME(sil-serialize-all) |
| public subscript(r: Range<Index>) -> SubSequence { |
| return Substring.${View}(_wholeString.${property}, _bounds: r) |
| } |
| } |
| |
| extension Substring { |
| % if View == 'CharacterView': |
| @available(swift, deprecated: 3.2, message: |
| "Please use String or Substring directly") |
| % end |
| @_inlineable // FIXME(sil-serialize-all) |
| public var ${property}: ${View} { |
| get { |
| return ${View}(_wholeString.${property}, _bounds: startIndex..<endIndex) |
| } |
| set { |
| self = Substring(newValue) |
| } |
| } |
| |
| /// Creates a Substring having the given content. |
| /// |
| /// - Complexity: O(1) |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(_ content: ${View}) { |
| self = content._wholeString[content.startIndex..<content.endIndex] |
| } |
| } |
| |
| extension String { |
| % if property in ('utf8', 'utf16'): |
| /// Creates a String having the given content. |
| /// |
| /// If `codeUnits` is an ill-formed code unit sequence, the result is `nil`. |
| /// |
| /// - Complexity: O(N), where N is the length of the resulting `String`'s |
| /// UTF-16. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init?(_ codeUnits: Substring.${View}) { |
| let wholeString = codeUnits._wholeString |
| guard |
| codeUnits.startIndex.samePosition(in: wholeString.unicodeScalars) != nil |
| && codeUnits.endIndex.samePosition(in: wholeString.unicodeScalars) != nil |
| else { return nil } |
| self = String(Substring(codeUnits)) |
| } |
| % else: |
| /// Creates a String having the given content. |
| /// |
| /// - Complexity: O(N), where N is the length of the resulting `String`'s |
| /// UTF-16. |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(_ content: Substring.${View}) { |
| self = String(Substring(content)) |
| } |
| % end |
| } |
| % end |
| |
| // FIXME: The other String views should be RangeReplaceable too. |
| extension Substring.UnicodeScalarView : RangeReplaceableCollection { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init() { _slice = Slice.init() } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public mutating func replaceSubrange<C : Collection>( |
| _ target: Range<Index>, with replacement: C |
| ) where C.Element == Element { |
| _slice.replaceSubrange(target, with: replacement) |
| } |
| } |
| |
| #if _runtime(_ObjC) |
| |
| extension Substring { |
| @_inlineable // FIXME(sil-serialize-all) |
| public func hasPrefix(_ prefix: String) -> Bool { |
| return String(self).hasPrefix(prefix) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func hasSuffix(_ suffix: String) -> Bool { |
| return String(self).hasSuffix(suffix) |
| } |
| } |
| |
| #endif |
| |
| extension Substring : RangeReplaceableCollection { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init<S : Sequence>(_ elements: S) |
| where S.Element == Character { |
| let e0 = elements as? _SwiftStringView |
| if _fastPath(e0 != nil), let e = e0 { |
| self = e._ephemeralContent[...] |
| } |
| else { |
| self = String(elements)[...] |
| } |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public mutating func append<S : Sequence>(contentsOf elements: S) |
| where S.Element == Character { |
| var c = self._ephemeralContent._core |
| self = Substring() |
| |
| let e0 = elements as? _SwiftStringView |
| if _fastPath(e0 != nil), let e1 = e0 { |
| c.append(contentsOf: e1._ephemeralContent.utf16) |
| self = String(c)[...] |
| } |
| else { |
| var s = String(c) |
| s.append(contentsOf: elements) |
| self = s[...] |
| } |
| } |
| } |
| |
| extension Substring { |
| @_inlineable // FIXME(sil-serialize-all) |
| public func lowercased() -> String { |
| return String(self).lowercased() |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func uppercased() -> String { |
| return String(self).uppercased() |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| public func filter( |
| _ isIncluded: (Element) throws -> Bool |
| ) rethrows -> String { |
| return try String(self.lazy.filter(isIncluded)) |
| } |
| } |
| |
| extension Substring : TextOutputStream { |
| @_inlineable // FIXME(sil-serialize-all) |
| public mutating func write(_ other: String) { |
| append(contentsOf: other) |
| } |
| } |
| |
| extension Substring : TextOutputStreamable { |
| @_inlineable // FIXME(sil-serialize-all) |
| public func write<Target : TextOutputStream>(to target: inout Target) { |
| target.write(String(self)) |
| } |
| } |
| |
| extension Substring : ExpressibleByUnicodeScalarLiteral { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(unicodeScalarLiteral value: String) { |
| self.init(_base: value, value.startIndex ..< value.endIndex) |
| } |
| } |
| extension Substring : ExpressibleByExtendedGraphemeClusterLiteral { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(extendedGraphemeClusterLiteral value: String) { |
| self.init(_base: value, value.startIndex ..< value.endIndex) |
| } |
| } |
| |
| extension Substring : ExpressibleByStringLiteral { |
| @_inlineable // FIXME(sil-serialize-all) |
| public init(stringLiteral value: String) { |
| self.init(_base: value, value.startIndex ..< value.endIndex) |
| } |
| } |
| |
| //===--- String/Substring Slicing Support ---------------------------------===// |
| /// In Swift 3.2, in the absence of type context, |
| /// |
| /// someString[someString.startIndex..<someString.endIndex] |
| /// |
| /// was deduced to be of type `String`. Therefore have a more-specific |
| /// Swift-3-only `subscript` overload on `String` (and `Substring`) that |
| /// continues to produce `String`. |
| extension String { |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, introduced: 4) |
| public subscript(r: Range<Index>) -> Substring { |
| return Substring( |
| _slice: Slice(base: self, bounds: r)) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, obsoleted: 4) |
| public subscript(bounds: Range<Index>) -> String { |
| return String(characters[bounds]) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, obsoleted: 4) |
| public subscript(bounds: ClosedRange<Index>) -> String { |
| return String(characters[bounds]) |
| } |
| } |
| |
| extension Substring { |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, introduced: 4) |
| public subscript(r: Range<Index>) -> Substring { |
| return Substring(_slice: _slice[r]) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, obsoleted: 4) |
| public subscript(bounds: Range<Index>) -> String { |
| return String(characters[bounds]) |
| } |
| |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, obsoleted: 4) |
| public subscript(bounds: ClosedRange<Index>) -> String { |
| return String(characters[bounds]) |
| } |
| } |
| //===----------------------------------------------------------------------===// |
| |
| // popFirst() is only present when a collection is its own subsequence. This was |
| // dropped in Swift 4. |
| extension String { |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, deprecated: 3.2, obsoleted: 4, message: |
| "Please use 'first', 'dropFirst()', or 'Substring.popFirst()'.") |
| public mutating func popFirst() -> String.Element? { |
| guard !isEmpty else { return nil } |
| let element = first! |
| let nextIdx = self.index(after: self.startIndex) |
| self = String(self[nextIdx...]) |
| return element |
| } |
| } |
| extension String._CharacterView { |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, deprecated: 3.2, obsoleted: 4, message: |
| "Please use 'first', 'dropFirst()', or 'Substring.CharacterView.popFirst()'.") |
| public mutating func popFirst() -> String._CharacterView.Element? { |
| guard !isEmpty else { return nil } |
| let element = first! |
| let nextIdx = self.index(after: self.startIndex) |
| self = String(self[nextIdx...])._characters |
| return element |
| } |
| } |
| extension String.UnicodeScalarView { |
| @_inlineable // FIXME(sil-serialize-all) |
| @available(swift, deprecated: 3.2, obsoleted: 4, message: |
| "Please use 'first', 'dropFirst()', or 'Substring.UnicodeScalarView.popFirst()'.") |
| public mutating func popFirst() -> String.UnicodeScalarView.Element? { |
| guard !isEmpty else { return nil } |
| let element = first! |
| let nextIdx = self.index(after: self.startIndex) |
| self = String(self[nextIdx...]).unicodeScalars |
| return element |
| } |
| } |