//===--- StringVariant.swift - Common operations on String storage views -===// // // 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 // //===----------------------------------------------------------------------===// @usableFromInline internal protocol _StringVariant : RandomAccessCollection where Element == Unicode.UTF16.CodeUnit, SubSequence == Self { // FIXME associatedtype Encoding : _UnicodeEncoding associatedtype CodeUnit : FixedWidthInteger & UnsignedInteger associatedtype UnicodeScalarIterator : IteratorProtocol where UnicodeScalarIterator.Element == Unicode.Scalar var isASCII: Bool { get } // Offset-based subscripts allow integer offsets within 0.. Element { get } subscript(offsetRange: Range) -> Self { get } func makeUnicodeScalarIterator() -> UnicodeScalarIterator // Measure the length in UTF-16 code units of the first extended grapheme // cluster in self. func measureFirstExtendedGraphemeCluster() -> Int // Measure the length in UTF-16 code units of the last extended grapheme // cluster in self. func measureLastExtendedGraphemeCluster() -> Int // Slow path for measuring the length in UTF-16 code units of the first // extended grapheme cluster in self. func _measureFirstExtendedGraphemeClusterSlow() -> Int // Slow path for measuring the length in UTF-16 code units of the last // extended grapheme cluster in self. func _measureLastExtendedGraphemeClusterSlow() -> Int func _copy( into target: UnsafeMutableBufferPointer ) where TargetCodeUnit : FixedWidthInteger & UnsignedInteger } extension _StringVariant { @inlinable // FIXME(sil-serialize-all) internal func _copyToNativeStorage( of codeUnit: TargetCodeUnit.Type = TargetCodeUnit.self, unusedCapacity: Int = 0 ) -> _SwiftStringStorage where TargetCodeUnit : FixedWidthInteger & UnsignedInteger { let storage = _SwiftStringStorage.create( capacity: count + unusedCapacity, count: count) _copy(into: storage.usedBuffer) return storage } @inlinable @inline(__always) func _boundsCheck(_ i: Index) { _precondition(i >= startIndex && i < endIndex, "String index is out of bounds") } @inlinable @inline(__always) func _boundsCheck(_ range: Range) { _precondition(range.lowerBound >= startIndex, "String index range is out of bounds") _precondition(range.upperBound <= endIndex, "String index range is out of bounds") } @inlinable @inline(__always) func _boundsCheck(offset i: Int) { _precondition(i >= 0 && i < count, "String index is out of bounds") } @inlinable @inline(__always) func _boundsCheck(offsetRange range: Range) { _precondition(range.lowerBound >= 0 && range.upperBound <= count, "String index range is out of bounds") } @inlinable internal func codeUnit(atCheckedIndex index: Index) -> Element { _boundsCheck(index) return self[index] } @inlinable internal func codeUnit(atCheckedOffset offset: Int) -> Element { _boundsCheck(offset: offset) return self[offset] } @inlinable internal func checkedSlice(_ range: Range) -> Self { _boundsCheck(offsetRange: range) return self[range] } @inlinable internal func checkedSlice(from startOffset: Int) -> Self { let r: Range = startOffset.. Self { let r: Range = 0.. Int { _boundsCheck(offset: offset) if _slowPath(UTF16.isLeadSurrogate(self[offset])) { if offset + 1 < self.count && UTF16.isTrailSurrogate(self[offset + 1]) { return 2 } } return 1 } @inlinable func unicodeScalarWidth(endingAt offset: Int) -> Int { _boundsCheck(offset: offset - 1) if _slowPath(UTF16.isTrailSurrogate(self[offset - 1])) { if offset >= 2 && UTF16.isLeadSurrogate(self[offset - 2]) { return 2 } } return 1 } @inlinable func unicodeScalar(startingAt offset: Int) -> Unicode.Scalar { let u0 = self.codeUnit(atCheckedOffset: offset) if _fastPath(UTF16._isScalar(u0)) { return Unicode.Scalar(_unchecked: UInt32(u0)) } if UTF16.isLeadSurrogate(u0) && offset + 1 < count { let u1 = self[offset + 1] if UTF16.isTrailSurrogate(u1) { return UTF16._decodeSurrogates(u0, u1) } } return Unicode.Scalar._replacementCharacter } @inlinable func unicodeScalar(endingAt offset: Int) -> Unicode.Scalar { let u1 = self.codeUnit(atCheckedOffset: offset - 1) if _fastPath(UTF16._isScalar(u1)) { return Unicode.Scalar(_unchecked: UInt32(u1)) } if UTF16.isTrailSurrogate(u1) && offset >= 2 { let u0 = self[offset - 2] if UTF16.isLeadSurrogate(u0) { return UTF16._decodeSurrogates(u0, u1) } } return Unicode.Scalar._replacementCharacter } }