//===--- 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. @_fixed_layout // FIXME(sil-serialize-all) public struct Index { @usableFromInline internal typealias _UTF8Buffer = UTF8.EncodedScalar @usableFromInline // FIXME(sil-serialize-all) internal var _compoundOffset: UInt64 @usableFromInline internal var _utf8Buffer = _UTF8Buffer() @usableFromInline internal var _graphemeStrideCache: UInt16 = 0 } } /// Convenience accessors extension String.Index { @inlinable // FIXME(sil-serialize-all) internal var utf8Buffer: String.Index._UTF8Buffer? { guard !_utf8Buffer.isEmpty else { return nil } return _utf8Buffer } @inlinable // FIXME(sil-serialize-all) internal var characterStride: Int? { guard _graphemeStrideCache > 0 else { return nil } return Int(truncatingIfNeeded: _graphemeStrideCache) } // TODO: Probably worth carving a bit for, or maybe a isSubScalar bit... @inlinable // FIXME(sil-serialize-all) internal var isUTF8: Bool { return self.utf8Buffer != nil || self.transcodedOffset > 0 } } extension String.Index : Equatable { // A combined code unit and transcoded offset, for comparison purposes @inlinable // FIXME(sil-serialize-all) internal var _orderingValue: UInt64 { return _compoundOffset } @inlinable // FIXME(sil-serialize-all) public static func == (lhs: String.Index, rhs: String.Index) -> Bool { return lhs._orderingValue == rhs._orderingValue } } extension String.Index : Comparable { @inlinable // FIXME(sil-serialize-all) public static func < (lhs: String.Index, rhs: String.Index) -> Bool { return lhs._orderingValue < rhs._orderingValue } } extension String.Index : Hashable { /// Hashes the essential components of this value by feeding them into the /// given hasher. /// /// - Parameter hasher: The hasher to use when combining the components /// of this instance. @inlinable public func hash(into hasher: inout Hasher) { hasher.combine(_orderingValue) } } extension String.Index { @inline(__always) @inlinable internal init(encodedOffset: Int, transcodedOffset: Int) { let cuOffset = UInt64(truncatingIfNeeded: encodedOffset) _sanityCheck( cuOffset & 0xFFFF_0000_0000_0000 == 0, "String length capped at 48bits") let transOffset = UInt64(truncatingIfNeeded: transcodedOffset) _sanityCheck(transOffset <= 4, "UTF-8 max transcoding is 4 code units") self._compoundOffset = cuOffset &<< 2 | transOffset } @inline(__always) @inlinable internal init(from other: String.Index, adjustingEncodedOffsetBy adj: Int) { self.init( encodedOffset: other.encodedOffset &+ adj, transcodedOffset: other.transcodedOffset) self._utf8Buffer = other._utf8Buffer self._graphemeStrideCache = other._graphemeStrideCache } /// Creates a new index at the specified UTF-16 offset. /// /// - Parameter offset: An offset in UTF-16 code units. @inlinable // FIXME(sil-serialize-all) public init(encodedOffset offset: Int) { self.init(encodedOffset: offset, transcodedOffset: 0) } @inlinable // FIXME(sil-serialize-all) internal init( encodedOffset offset: Int, transcodedOffset: Int, buffer: _UTF8Buffer ) { self.init(encodedOffset: offset, transcodedOffset: transcodedOffset) self._utf8Buffer = buffer } @inlinable internal init(encodedOffset: Int, characterStride: Int) { self.init(encodedOffset: encodedOffset, transcodedOffset: 0) if characterStride < UInt16.max { self._graphemeStrideCache = UInt16(truncatingIfNeeded: characterStride) } } /// The offset into a string's UTF-16 encoding for this index. @inlinable // FIXME(sil-serialize-all) public var encodedOffset : Int { return Int(truncatingIfNeeded: _compoundOffset &>> 2) } /// The offset of this index within whatever encoding this is being viewed as @inlinable // FIXME(sil-serialize-all) internal var transcodedOffset: Int { return Int(truncatingIfNeeded: _compoundOffset & 0x3) } }