| //===--- StringIndex.swift ------------------------------------------------===// |
| // |
| // 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 { |
| /// A position of a character or code unit in a string. |
| public struct Index { |
| internal var _compoundOffset : UInt64 |
| @_versioned |
| internal var _cache: _Cache |
| |
| internal typealias _UTF8Buffer = _ValidUTF8Buffer<UInt64> |
| @_versioned |
| internal enum _Cache { |
| case utf16 |
| case utf8(buffer: _UTF8Buffer) |
| case character(stride: UInt16) |
| case unicodeScalar(value: Unicode.Scalar) |
| } |
| } |
| } |
| |
| /// Convenience accessors |
| extension String.Index._Cache { |
| @_versioned |
| var utf16: Void? { |
| if case .utf16 = self { return () } else { return nil } |
| } |
| @_versioned |
| var utf8: String.Index._UTF8Buffer? { |
| if case .utf8(let r) = self { return r } else { return nil } |
| } |
| @_versioned |
| var character: UInt16? { |
| if case .character(let r) = self { return r } else { return nil } |
| } |
| @_versioned |
| var unicodeScalar: UnicodeScalar? { |
| if case .unicodeScalar(let r) = self { return r } else { return nil } |
| } |
| } |
| |
| extension String.Index : Equatable { |
| public static func == (lhs: String.Index, rhs: String.Index) -> Bool { |
| return lhs._compoundOffset == rhs._compoundOffset |
| } |
| } |
| |
| extension String.Index : Comparable { |
| public static func < (lhs: String.Index, rhs: String.Index) -> Bool { |
| return lhs._compoundOffset < rhs._compoundOffset |
| } |
| } |
| |
| extension String.Index { |
| internal typealias _Self = String.Index |
| |
| /// Creates a new index at the specified UTF-16 offset. |
| /// |
| /// - Parameter offset: An offset in UTF-16 code units. |
| public init(encodedOffset offset: Int) { |
| _compoundOffset = UInt64(offset << _Self._strideBits) |
| _cache = .utf16 |
| } |
| |
| @_versioned |
| internal init(encodedOffset o: Int, transcodedOffset: Int = 0, _ c: _Cache) { |
| _compoundOffset = UInt64(o << _Self._strideBits | transcodedOffset) |
| _cache = c |
| } |
| |
| internal static var _strideBits : Int { return 2 } |
| internal static var _mask : UInt64 { return (1 &<< _Self._strideBits) &- 1 } |
| |
| internal mutating func _setEncodedOffset(_ x: Int) { |
| _compoundOffset = UInt64(x << _Self._strideBits) |
| } |
| |
| /// The offset into a string's UTF-16 encoding for this index. |
| public var encodedOffset : Int { |
| return Int(_compoundOffset >> _Self._strideBits) |
| } |
| |
| /// The offset of this index within whatever encoding this is being viewed as |
| @_versioned |
| internal var _transcodedOffset : Int { |
| get { |
| return Int(_compoundOffset & _Self._mask) |
| } |
| set { |
| let extended = UInt64(newValue) |
| _sanityCheck(extended <= _Self._mask) |
| _compoundOffset &= ~_Self._mask |
| _compoundOffset |= extended |
| } |
| } |
| } |
| |
| // SPI for Foundation |
| extension String.Index { |
| @available(swift, deprecated: 3.2) |
| @available(swift, obsoleted: 4.0) |
| public // SPI(Foundation) |
| init(_position: Int) { |
| self.init(encodedOffset: _position) |
| } |
| |
| @available(swift, deprecated: 3.2) |
| @available(swift, obsoleted: 4.0) |
| public // SPI(Foundation) |
| init(_offset: Int) { |
| self.init(encodedOffset: _offset) |
| } |
| |
| @available(swift, deprecated: 3.2) |
| @available(swift, obsoleted: 4.0) |
| public // SPI(Foundation) |
| init(_base: String.Index, in c: String.CharacterView) { |
| self = _base |
| } |
| |
| /// The integer offset of this index in UTF-16 code units. |
| @available(swift, deprecated: 3.2) |
| @available(swift, obsoleted: 4.0) |
| public // SPI(Foundation) |
| var _utf16Index: Int { |
| return self.encodedOffset |
| } |
| |
| /// The integer offset of this index in UTF-16 code units. |
| @available(swift, deprecated: 3.2) |
| @available(swift, obsoleted: 4.0) |
| public // SPI(Foundation) |
| var _offset: Int { |
| return self.encodedOffset |
| } |
| } |
| |
| |
| // backward compatibility for index interchange. |
| extension Optional where Wrapped == String.Index { |
| @available( |
| swift, obsoleted: 4.0, |
| message: "Any String view index conversion can fail in Swift 4; please unwrap the optional indices") |
| public static func ..<( |
| lhs: String.Index?, rhs: String.Index? |
| ) -> Range<String.Index> { |
| return lhs! ..< rhs! |
| } |
| |
| @available( |
| swift, obsoleted: 4.0, |
| message: "Any String view index conversion can fail in Swift 4; please unwrap the optional indices") |
| public static func ...( |
| lhs: String.Index?, rhs: String.Index? |
| ) -> ClosedRange<String.Index> { |
| return lhs! ... rhs! |
| } |
| } |