Merge pull request #22695 from milseman/5_0_en_gadus_offset
[5.0][String.Index] Deprecate encodedOffset var/init
diff --git a/stdlib/public/SDK/Foundation/URLComponents.swift b/stdlib/public/SDK/Foundation/URLComponents.swift
index 2d6eabf..2ba4914 100644
--- a/stdlib/public/SDK/Foundation/URLComponents.swift
+++ b/stdlib/public/SDK/Foundation/URLComponents.swift
@@ -192,16 +192,8 @@
@available(macOS 10.11, iOS 9.0, *)
private func _toStringRange(_ r : NSRange) -> Range<String.Index>? {
- guard r.location != NSNotFound else { return nil }
-
- let utf16Start = String.UTF16View.Index(encodedOffset: r.location)
- let utf16End = String.UTF16View.Index(encodedOffset: r.location + r.length)
-
guard let s = self.string else { return nil }
- guard let start = String.Index(utf16Start, within: s) else { return nil }
- guard let end = String.Index(utf16End, within: s) else { return nil }
-
- return start..<end
+ return Range(r, in: s)
}
/// Returns the character range of the scheme in the string returned by `var string`.
diff --git a/stdlib/public/SDK/NaturalLanguage/NLTagger.swift b/stdlib/public/SDK/NaturalLanguage/NLTagger.swift
index a4e39a3..138d448 100644
--- a/stdlib/public/SDK/NaturalLanguage/NLTagger.swift
+++ b/stdlib/public/SDK/NaturalLanguage/NLTagger.swift
@@ -18,7 +18,7 @@
@nonobjc
public func tokenRange(at index: String.Index, unit: NLTokenUnit) -> Range<String.Index> {
let str = self.string ?? ""
- let characterIndex = index.encodedOffset
+ let characterIndex = index.utf16Offset(in: str)
let nsrange = self.__tokenRange(at: characterIndex, unit: unit)
return Range(nsrange, in: str)!
}
@@ -26,7 +26,7 @@
@nonobjc
public func tag(at index: String.Index, unit: NLTokenUnit, scheme: NLTagScheme) -> (NLTag?, Range<String.Index>) {
let str = self.string ?? ""
- let characterIndex = index.encodedOffset
+ let characterIndex = index.utf16Offset(in: str)
let rangePointer = NSRangePointer.allocate(capacity: 1)
rangePointer.initialize(to: NSMakeRange(0, 0))
let tag = self.__tag(at: characterIndex, unit: unit, scheme: scheme, tokenRange: rangePointer)
diff --git a/stdlib/public/SDK/NaturalLanguage/NLTokenizer.swift b/stdlib/public/SDK/NaturalLanguage/NLTokenizer.swift
index 0cfc2e6..ca8b337 100644
--- a/stdlib/public/SDK/NaturalLanguage/NLTokenizer.swift
+++ b/stdlib/public/SDK/NaturalLanguage/NLTokenizer.swift
@@ -18,7 +18,7 @@
@nonobjc
public func tokenRange(at index: String.Index) -> Range<String.Index> {
let str = self.string ?? ""
- let characterIndex = index.encodedOffset
+ let characterIndex = index.utf16Offset(in: str)
let nsrange = self.__tokenRange(at:characterIndex)
return Range(nsrange, in: str)!
}
diff --git a/stdlib/public/core/String.swift b/stdlib/public/core/String.swift
index 0bc6342..c3d93ed 100644
--- a/stdlib/public/core/String.swift
+++ b/stdlib/public/core/String.swift
@@ -923,8 +923,8 @@
var icuInputBuffer = icuInputBuffer
var icuOutputBuffer = icuOutputBuffer
- var index = String.Index(encodedOffset: 0)
- let cachedEndIndex = String.Index(encodedOffset: sourceBuffer.count)
+ var index = String.Index(_encodedOffset: 0)
+ let cachedEndIndex = String.Index(_encodedOffset: sourceBuffer.count)
var hasBufferOwnership = false
diff --git a/stdlib/public/core/StringBreadcrumbs.swift b/stdlib/public/core/StringBreadcrumbs.swift
index 5e8625d..1ecae71 100644
--- a/stdlib/public/core/StringBreadcrumbs.swift
+++ b/stdlib/public/core/StringBreadcrumbs.swift
@@ -79,8 +79,8 @@
internal func getBreadcrumb(
forIndex idx: String.Index
) -> (lowerBound: String.Index, offset: Int) {
- var lowerBound = idx.encodedOffset / 3 / stride
- var upperBound = Swift.min(1 + (idx.encodedOffset / stride), crumbs.count)
+ var lowerBound = idx._encodedOffset / 3 / stride
+ var upperBound = Swift.min(1 + (idx._encodedOffset / stride), crumbs.count)
_internalInvariant(crumbs[lowerBound] <= idx)
_internalInvariant(upperBound == crumbs.count || crumbs[upperBound] >= idx)
diff --git a/stdlib/public/core/StringCharacterView.swift b/stdlib/public/core/StringCharacterView.swift
index 154dc4f..d25e984 100644
--- a/stdlib/public/core/StringCharacterView.swift
+++ b/stdlib/public/core/StringCharacterView.swift
@@ -66,9 +66,9 @@
// TODO: known-ASCII fast path, single-scalar-grapheme fast path, etc.
let stride = _characterStride(startingAt: i)
- let nextOffset = i.encodedOffset &+ stride
+ let nextOffset = i._encodedOffset &+ stride
let nextStride = _characterStride(
- startingAt: Index(encodedOffset: nextOffset))
+ startingAt: Index(_encodedOffset: nextOffset))
return Index(
encodedOffset: nextOffset, characterStride: nextStride)
@@ -84,7 +84,7 @@
// TODO: known-ASCII fast path, single-scalar-grapheme fast path, etc.
let stride = _characterStride(endingAt: i)
- let priorOffset = i.encodedOffset &- stride
+ let priorOffset = i._encodedOffset &- stride
return Index(encodedOffset: priorOffset, characterStride: stride)
}
/// Returns an index that is the specified distance from the given index.
@@ -198,7 +198,7 @@
let i = _guts.scalarAlign(i)
let distance = _characterStride(startingAt: i)
return _guts.errorCorrectedCharacter(
- startingAt: i.encodedOffset, endingAt: i.encodedOffset &+ distance)
+ startingAt: i._encodedOffset, endingAt: i._encodedOffset &+ distance)
}
}
@@ -209,14 +209,14 @@
if i == endIndex { return 0 }
- return _guts._opaqueCharacterStride(startingAt: i.encodedOffset)
+ return _guts._opaqueCharacterStride(startingAt: i._encodedOffset)
}
@inlinable @inline(__always)
internal func _characterStride(endingAt i: Index) -> Int {
if i == startIndex { return 0 }
- return _guts._opaqueCharacterStride(endingAt: i.encodedOffset)
+ return _guts._opaqueCharacterStride(endingAt: i._encodedOffset)
}
}
diff --git a/stdlib/public/core/StringComparison.swift b/stdlib/public/core/StringComparison.swift
index 42b749d..3f776bf 100644
--- a/stdlib/public/core/StringComparison.swift
+++ b/stdlib/public/core/StringComparison.swift
@@ -328,10 +328,10 @@
if _fastPath(self.isFastUTF8 && other.isFastUTF8) {
return self.withFastUTF8 { leftUTF8 in
other.withFastUTF8 { rightUTF8 in
- let leftStartIndex = String.Index(encodedOffset: 0)
- let rightStartIndex = String.Index(encodedOffset: 0)
- let leftEndIndex = String.Index(encodedOffset: leftUTF8.count)
- let rightEndIndex = String.Index(encodedOffset: rightUTF8.count)
+ let leftStartIndex = String.Index(_encodedOffset: 0)
+ let rightStartIndex = String.Index(_encodedOffset: 0)
+ let leftEndIndex = String.Index(_encodedOffset: leftUTF8.count)
+ let rightEndIndex = String.Index(_encodedOffset: rightUTF8.count)
return _normalizedCompareImpl(
left_outputBuffer: _castOutputBuffer(&left_output),
left_icuInputBuffer: _castOutputBuffer(&left_icuInput),
diff --git a/stdlib/public/core/StringGraphemeBreaking.swift b/stdlib/public/core/StringGraphemeBreaking.swift
index 047185b..21222e8 100644
--- a/stdlib/public/core/StringGraphemeBreaking.swift
+++ b/stdlib/public/core/StringGraphemeBreaking.swift
@@ -156,7 +156,7 @@
internal func isOnGraphemeClusterBoundary(_ i: String.Index) -> Bool {
guard i.transcodedOffset == 0 else { return false }
- let offset = i.encodedOffset
+ let offset = i._encodedOffset
if offset == 0 || offset == self.count { return true }
guard isOnUnicodeScalarBoundary(i) else { return false }
@@ -197,7 +197,7 @@
let count = _object.largeCount
let cocoa = _object.cocoaObject
- let startIdx = String.Index(encodedOffset: i)
+ let startIdx = String.Index(_encodedOffset: i)
let (sc1, len) = foreignErrorCorrectedScalar(startingAt: startIdx)
if i &+ len == count {
// Last scalar is last grapheme
@@ -263,7 +263,7 @@
let count = _object.largeCount
let cocoa = _object.cocoaObject
- let endIdx = String.Index(encodedOffset: i)
+ let endIdx = String.Index(_encodedOffset: i)
let (sc2, len) = foreignErrorCorrectedScalar(endingAt: endIdx)
if i &- len == 0 {
// First scalar is first grapheme
diff --git a/stdlib/public/core/StringGuts.swift b/stdlib/public/core/StringGuts.swift
index f90a886..0b4b580 100644
--- a/stdlib/public/core/StringGuts.swift
+++ b/stdlib/public/core/StringGuts.swift
@@ -274,11 +274,11 @@
@inlinable
internal var startIndex: String.Index {
- @inline(__always) get { return Index(encodedOffset: 0) }
+ @inline(__always) get { return Index(_encodedOffset: 0) }
}
@inlinable
internal var endIndex: String.Index {
- @inline(__always) get { return Index(encodedOffset: self.count) }
+ @inline(__always) get { return Index(_encodedOffset: self.count) }
}
}
diff --git a/stdlib/public/core/StringGutsRangeReplaceable.swift b/stdlib/public/core/StringGutsRangeReplaceable.swift
index fc27b12..67f524a 100644
--- a/stdlib/public/core/StringGutsRangeReplaceable.swift
+++ b/stdlib/public/core/StringGutsRangeReplaceable.swift
@@ -218,8 +218,8 @@
}
internal mutating func remove(from lower: Index, to upper: Index) {
- let lowerOffset = lower.encodedOffset
- let upperOffset = upper.encodedOffset
+ let lowerOffset = lower._encodedOffset
+ let upperOffset = upper._encodedOffset
_internalInvariant(lower.transcodedOffset == 0 && upper.transcodedOffset == 0)
_internalInvariant(lowerOffset <= upperOffset && upperOffset <= self.count)
@@ -279,16 +279,16 @@
isASCII: Bool
) {
let neededCapacity =
- bounds.lowerBound.encodedOffset
- + codeUnits.count + (self.count - bounds.upperBound.encodedOffset)
+ bounds.lowerBound._encodedOffset
+ + codeUnits.count + (self.count - bounds.upperBound._encodedOffset)
reserveCapacity(neededCapacity)
_internalInvariant(bounds.lowerBound.transcodedOffset == 0)
_internalInvariant(bounds.upperBound.transcodedOffset == 0)
_object.nativeStorage.replace(
- from: bounds.lowerBound.encodedOffset,
- to: bounds.upperBound.encodedOffset,
+ from: bounds.lowerBound._encodedOffset,
+ to: bounds.upperBound._encodedOffset,
with: codeUnits)
self = _StringGuts(_object.nativeStorage)
}
@@ -300,16 +300,16 @@
let replCount = codeUnits.count
let neededCapacity =
- bounds.lowerBound.encodedOffset
- + replCount + (self.count - bounds.upperBound.encodedOffset)
+ bounds.lowerBound._encodedOffset
+ + replCount + (self.count - bounds.upperBound._encodedOffset)
reserveCapacity(neededCapacity)
_internalInvariant(bounds.lowerBound.transcodedOffset == 0)
_internalInvariant(bounds.upperBound.transcodedOffset == 0)
_object.nativeStorage.replace(
- from: bounds.lowerBound.encodedOffset,
- to: bounds.upperBound.encodedOffset,
+ from: bounds.lowerBound._encodedOffset,
+ to: bounds.upperBound._encodedOffset,
with: codeUnits,
replacementCount: replCount)
self = _StringGuts(_object.nativeStorage)
diff --git a/stdlib/public/core/StringGutsSlice.swift b/stdlib/public/core/StringGutsSlice.swift
index 3c6d25d4..614c294 100644
--- a/stdlib/public/core/StringGutsSlice.swift
+++ b/stdlib/public/core/StringGutsSlice.swift
@@ -74,8 +74,8 @@
@inlinable
internal var range: Range<String.Index> {
@inline(__always) get {
- return String.Index(encodedOffset: _offsetRange.lowerBound)
- ..< String.Index(encodedOffset: _offsetRange.upperBound)
+ return String.Index(_encodedOffset: _offsetRange.lowerBound)
+ ..< String.Index(_encodedOffset: _offsetRange.upperBound)
}
}
diff --git a/stdlib/public/core/StringIndex.swift b/stdlib/public/core/StringIndex.swift
index c1e8d0f..7974004 100644
--- a/stdlib/public/core/StringIndex.swift
+++ b/stdlib/public/core/StringIndex.swift
@@ -62,10 +62,22 @@
@inline(__always) get { return orderingValue == 0 }
}
+ /// The UTF-16 code unit offset corresponding to this Index
+ public func utf16Offset<S: StringProtocol>(in s: S) -> Int {
+ return s.utf16.distance(from: s.utf16.startIndex, to: self)
+ }
+
/// The offset into a string's code units for this index.
+ @available(swift, deprecated: 4.2, message: """
+ encodedOffset has been deprecated as most common usage is incorrect. \
+ Use utf16Offset(in:) to achieve the same behavior.
+ """)
@inlinable
- public var encodedOffset: Int {
- @inline(__always) get { return Int(truncatingIfNeeded: _rawBits &>> 16) }
+ public var encodedOffset: Int { return _encodedOffset }
+
+ @inlinable @inline(__always)
+ internal var _encodedOffset: Int {
+ return Int(truncatingIfNeeded: _rawBits &>> 16)
}
@inlinable
@@ -91,12 +103,35 @@
self.init((pos &<< 16) | (trans &<< 14))
}
+ /// Creates a new index at the specified UTF-16 code unit offset
+ ///
+ /// - Parameter offset: An offset in UTF-16 code units.
+ public init<S: StringProtocol>(utf16Offset offset: Int, in s: S) {
+ let (start, end) = (s.utf16.startIndex, s.utf16.endIndex)
+ guard offset >= 0,
+ let idx = s.utf16.index(start, offsetBy: offset, limitedBy: end)
+ else {
+ self = end.nextEncoded
+ return
+ }
+ self = idx
+ }
+
/// Creates a new index at the specified code unit offset.
///
/// - Parameter offset: An offset in code units.
+ @available(swift, deprecated: 4.2, message: """
+ encodedOffset has been deprecated as most common usage is incorrect. \
+ Use String.Index(utf16Offset:in:) to achieve the same behavior.
+ """)
+ @inlinable
+ public init(encodedOffset offset: Int) {
+ self.init(_encodedOffset: offset)
+ }
+
@inlinable @inline(__always)
- public init(encodedOffset: Int) {
- self.init(encodedOffset: encodedOffset, transcodedOffset: 0)
+ internal init(_encodedOffset offset: Int) {
+ self.init(encodedOffset: offset, transcodedOffset: 0)
}
@usableFromInline
@@ -121,7 +156,7 @@
#else
@usableFromInline @inline(never) @_effects(releasenone)
internal func _invariantCheck() {
- _internalInvariant(encodedOffset >= 0)
+ _internalInvariant(_encodedOffset >= 0)
}
#endif // INTERNAL_CHECKS_ENABLED
}
@@ -132,7 +167,7 @@
@inlinable
internal var strippingTranscoding: String.Index {
@inline(__always) get {
- return String.Index(encodedOffset: self.encodedOffset)
+ return String.Index(_encodedOffset: self._encodedOffset)
}
}
@@ -140,7 +175,7 @@
internal var nextEncoded: String.Index {
@inline(__always) get {
_internalInvariant(self.transcodedOffset == 0)
- return String.Index(encodedOffset: self.encodedOffset &+ 1)
+ return String.Index(_encodedOffset: self._encodedOffset &+ 1)
}
}
@@ -148,7 +183,7 @@
internal var priorEncoded: String.Index {
@inline(__always) get {
_internalInvariant(self.transcodedOffset == 0)
- return String.Index(encodedOffset: self.encodedOffset &- 1)
+ return String.Index(_encodedOffset: self._encodedOffset &- 1)
}
}
@@ -156,7 +191,7 @@
internal var nextTranscoded: String.Index {
@inline(__always) get {
return String.Index(
- encodedOffset: self.encodedOffset,
+ encodedOffset: self._encodedOffset,
transcodedOffset: self.transcodedOffset &+ 1)
}
}
@@ -165,7 +200,7 @@
internal var priorTranscoded: String.Index {
@inline(__always) get {
return String.Index(
- encodedOffset: self.encodedOffset,
+ encodedOffset: self._encodedOffset,
transcodedOffset: self.transcodedOffset &- 1)
}
}
@@ -174,13 +209,13 @@
// Note: strips any transcoded offset.
@inlinable @inline(__always)
internal func encoded(offsetBy n: Int) -> String.Index {
- return String.Index(encodedOffset: self.encodedOffset &+ n)
+ return String.Index(_encodedOffset: self._encodedOffset &+ n)
}
@inlinable @inline(__always)
internal func transcoded(withOffset n: Int) -> String.Index {
_internalInvariant(self.transcodedOffset == 0)
- return String.Index(encodedOffset: self.encodedOffset, transcodedOffset: n)
+ return String.Index(encodedOffset: self._encodedOffset, transcodedOffset: n)
}
}
diff --git a/stdlib/public/core/StringNormalization.swift b/stdlib/public/core/StringNormalization.swift
index 199225c..c4330b4 100644
--- a/stdlib/public/core/StringNormalization.swift
+++ b/stdlib/public/core/StringNormalization.swift
@@ -94,7 +94,7 @@
internal func foreignHasNormalizationBoundary(
before index: String.Index
) -> Bool {
- let offset = index.encodedOffset
+ let offset = index._encodedOffset
if offset == 0 || offset == count {
return true
}
@@ -350,11 +350,11 @@
icuInputBuffer: inout UnsafeMutableBufferPointer<UInt16>,
icuOutputBuffer: inout UnsafeMutableBufferPointer<UInt16>
) -> NormalizationResult {
- let start = readIndex.encodedOffset
+ let start = readIndex._encodedOffset
let rebasedSourceBuffer = UnsafeBufferPointer(rebasing: sourceBuffer[start...])
if let (read, filled) = fastFill(rebasedSourceBuffer, outputBuffer) {
let nextIndex = readIndex.encoded(offsetBy: read)
- _internalInvariant(sourceBuffer.isOnUnicodeScalarBoundary(nextIndex.encodedOffset))
+ _internalInvariant(sourceBuffer.isOnUnicodeScalarBoundary(nextIndex._encodedOffset))
return NormalizationResult(
amountFilled: filled, nextReadPosition: nextIndex, allocatedBuffers: false)
@@ -384,7 +384,7 @@
}
let nextIndex = readIndex.encoded(offsetBy: read)
- _internalInvariant(sourceBuffer.isOnUnicodeScalarBoundary(nextIndex.encodedOffset))
+ _internalInvariant(sourceBuffer.isOnUnicodeScalarBoundary(nextIndex._encodedOffset))
let normalized = performWithAllocationIfNecessary(preserving: .icuInput) { () -> Int? in
return _tryNormalize(
@@ -426,8 +426,8 @@
return f()!
}
let (read, filled) = performWithAllocationIfNecessary(preserving: .none) { () -> (Int, Int)? in
- let start = readIndex.encodedOffset
- let end = endIndex.encodedOffset
+ let start = readIndex._encodedOffset
+ let end = endIndex._encodedOffset
return copyUTF16Segment(boundedBy: start..<end, into: icuInputBuffer) { gutsOffset in
return guts.errorCorrectedScalar(startingAt: gutsOffset)
}
diff --git a/stdlib/public/core/StringProtocol.swift b/stdlib/public/core/StringProtocol.swift
index 433f104..4e31396 100644
--- a/stdlib/public/core/StringProtocol.swift
+++ b/stdlib/public/core/StringProtocol.swift
@@ -153,7 +153,7 @@
let end = endIndex
_internalInvariant(
start.transcodedOffset == 0 && end.transcodedOffset == 0)
- return Range(uncheckedBounds: (start.encodedOffset, end.encodedOffset))
+ return Range(uncheckedBounds: (start._encodedOffset, end._encodedOffset))
}
}
diff --git a/stdlib/public/core/StringRangeReplaceableCollection.swift b/stdlib/public/core/StringRangeReplaceableCollection.swift
index 6981d17..0edbd51 100644
--- a/stdlib/public/core/StringRangeReplaceableCollection.swift
+++ b/stdlib/public/core/StringRangeReplaceableCollection.swift
@@ -298,23 +298,23 @@
extension String {
@inlinable @inline(__always)
internal func _boundsCheck(_ index: Index) {
- _precondition(index.encodedOffset >= 0 && index.encodedOffset < _guts.count,
+ _precondition(index._encodedOffset >= 0 && index._encodedOffset < _guts.count,
"String index is out of bounds")
}
@inlinable @inline(__always)
internal func _boundsCheck(_ range: Range<Index>) {
_precondition(
- range.lowerBound.encodedOffset >= 0 &&
- range.upperBound.encodedOffset <= _guts.count,
+ range.lowerBound._encodedOffset >= 0 &&
+ range.upperBound._encodedOffset <= _guts.count,
"String index range is out of bounds")
}
@inlinable @inline(__always)
internal func _boundsCheck(_ range: ClosedRange<Index>) {
_precondition(
- range.lowerBound.encodedOffset >= 0 &&
- range.upperBound.encodedOffset < _guts.count,
+ range.lowerBound._encodedOffset >= 0 &&
+ range.upperBound._encodedOffset < _guts.count,
"String index range is out of bounds")
}
}
diff --git a/stdlib/public/core/StringUTF16View.swift b/stdlib/public/core/StringUTF16View.swift
index 0cbd168..da372d3 100644
--- a/stdlib/public/core/StringUTF16View.swift
+++ b/stdlib/public/core/StringUTF16View.swift
@@ -149,7 +149,7 @@
// For a BMP scalar (1-3 UTF-8 code units), advance past it. For a non-BMP
// scalar, use a transcoded offset first.
- let len = _guts.fastUTF8ScalarLength(startingAt: i.encodedOffset)
+ let len = _guts.fastUTF8ScalarLength(startingAt: i._encodedOffset)
if len == 4 && i.transcodedOffset == 0 {
return i.nextTranscoded
}
@@ -167,7 +167,7 @@
return i.strippingTranscoding
}
- let len = _guts.fastUTF8ScalarLength(endingAt: i.encodedOffset)
+ let len = _guts.fastUTF8ScalarLength(endingAt: i._encodedOffset)
if len == 4 {
// 2 UTF-16 code units comprise this scalar; advance to the beginning and
// start mid-scalar transcoding
@@ -249,7 +249,7 @@
if _fastPath(_guts.isFastUTF8) {
let scalar = _guts.fastUTF8Scalar(
- startingAt: _guts.scalarAlign(i).encodedOffset)
+ startingAt: _guts.scalarAlign(i)._encodedOffset)
if scalar.value <= 0xFFFF {
return UInt16(truncatingIfNeeded: scalar.value)
}
@@ -455,7 +455,7 @@
@_effects(releasenone)
internal func _foreignDistance(from start: Index, to end: Index) -> Int {
_internalInvariant(_guts.isForeign)
- return end.encodedOffset - start.encodedOffset
+ return end._encodedOffset - start._encodedOffset
}
@usableFromInline @inline(never)
@@ -464,7 +464,7 @@
_ i: Index, offsetBy n: Int, limitedBy limit: Index
) -> Index? {
_internalInvariant(_guts.isForeign)
- let l = limit.encodedOffset - i.encodedOffset
+ let l = limit._encodedOffset - i._encodedOffset
if n > 0 ? l >= 0 && l < n : l <= 0 && n < l {
return nil
}
@@ -482,7 +482,7 @@
@_effects(releasenone)
internal func _foreignCount() -> Int {
_internalInvariant(_guts.isForeign)
- return endIndex.encodedOffset - startIndex.encodedOffset
+ return endIndex._encodedOffset - startIndex._encodedOffset
}
}
@@ -511,10 +511,10 @@
if _guts.isASCII {
_internalInvariant(idx.transcodedOffset == 0)
- return idx.encodedOffset
+ return idx._encodedOffset
}
- if idx.encodedOffset < _shortHeuristic || !_guts.hasBreadcrumbs {
+ if idx._encodedOffset < _shortHeuristic || !_guts.hasBreadcrumbs {
return _distance(from: startIndex, to: idx)
}
@@ -534,7 +534,7 @@
// Trivial and common: start
if offset == 0 { return startIndex }
- if _guts.isASCII { return Index(encodedOffset: offset) }
+ if _guts.isASCII { return Index(_encodedOffset: offset) }
if offset < _shortHeuristic || !_guts.hasBreadcrumbs {
return _index(startIndex, offsetBy: offset)
@@ -550,7 +550,7 @@
if remaining == 0 { return crumb }
return _guts.withFastUTF8 { utf8 in
- var readIdx = crumb.encodedOffset
+ var readIdx = crumb._encodedOffset
let readEnd = utf8.count
_internalInvariant(readIdx < readEnd)
@@ -575,7 +575,7 @@
_internalInvariant(utf16Len == 2)
return Index(encodedOffset: readIdx, transcodedOffset: 1)
}
- return Index(encodedOffset: readIdx &+ len)
+ return Index(_encodedOffset: readIdx &+ len)
}
readIdx &+= len
@@ -598,8 +598,8 @@
return _guts.withFastUTF8 { utf8 in
var writeIdx = 0
let writeEnd = buffer.count
- var readIdx = range.lowerBound.encodedOffset
- let readEnd = range.upperBound.encodedOffset
+ var readIdx = range.lowerBound._encodedOffset
+ let readEnd = range.upperBound._encodedOffset
if isASCII {
_internalInvariant(range.lowerBound.transcodedOffset == 0)
diff --git a/stdlib/public/core/StringUTF8View.swift b/stdlib/public/core/StringUTF8View.swift
index c76ed18..6addee3 100644
--- a/stdlib/public/core/StringUTF8View.swift
+++ b/stdlib/public/core/StringUTF8View.swift
@@ -160,7 +160,7 @@
@inlinable @inline(__always)
public func index(_ i: Index, offsetBy n: Int) -> Index {
if _fastPath(_guts.isFastUTF8) {
- _precondition(n + i.encodedOffset <= _guts.count)
+ _precondition(n + i._encodedOffset <= _guts.count)
return i.encoded(offsetBy: n)
}
@@ -175,15 +175,15 @@
// Check the limit: ignore limit if it precedes `i` (in the correct
// direction), otherwise must not be beyond limit (in the correct
// direction).
- let iOffset = i.encodedOffset
+ let iOffset = i._encodedOffset
let result = iOffset + n
- let limitOffset = limit.encodedOffset
+ let limitOffset = limit._encodedOffset
if n >= 0 {
guard limitOffset < iOffset || result <= limitOffset else { return nil }
} else {
guard limitOffset > iOffset || result >= limitOffset else { return nil }
}
- return Index(encodedOffset: result)
+ return Index(_encodedOffset: result)
}
return _foreignIndex(i, offsetBy: n, limitedBy: limit)
@@ -192,7 +192,7 @@
@inlinable @inline(__always)
public func distance(from i: Index, to j: Index) -> Int {
if _fastPath(_guts.isFastUTF8) {
- return j.encodedOffset &- i.encodedOffset
+ return j._encodedOffset &- i._encodedOffset
}
return _foreignDistance(from: i, to: j)
}
@@ -214,7 +214,7 @@
@inline(__always) get {
String(_guts)._boundsCheck(i)
if _fastPath(_guts.isFastUTF8) {
- return _guts.withFastUTF8 { utf8 in utf8[_unchecked: i.encodedOffset] }
+ return _guts.withFastUTF8 { utf8 in utf8[_unchecked: i._encodedOffset] }
}
return _foreignSubscript(position: i)
diff --git a/stdlib/public/core/StringUnicodeScalarView.swift b/stdlib/public/core/StringUnicodeScalarView.swift
index ee3d68e..48465ea 100644
--- a/stdlib/public/core/StringUnicodeScalarView.swift
+++ b/stdlib/public/core/StringUnicodeScalarView.swift
@@ -114,7 +114,7 @@
// TODO(String performance): isASCII fast-path
if _fastPath(_guts.isFastUTF8) {
- let len = _guts.fastUTF8ScalarLength(startingAt: i.encodedOffset)
+ let len = _guts.fastUTF8ScalarLength(startingAt: i._encodedOffset)
return i.encoded(offsetBy: len)
}
@@ -126,12 +126,12 @@
/// - Precondition: The previous location exists.
@inlinable @inline(__always)
public func index(before i: Index) -> Index {
- precondition(i.encodedOffset > 0)
+ precondition(i._encodedOffset > 0)
// TODO(String performance): isASCII fast-path
if _fastPath(_guts.isFastUTF8) {
let len = _guts.withFastUTF8 { utf8 -> Int in
- return _utf8ScalarLength(utf8, endingAt: i.encodedOffset)
+ return _utf8ScalarLength(utf8, endingAt: i._encodedOffset)
}
_internalInvariant(len <= 4, "invalid UTF8")
return i.encoded(offsetBy: -len)
@@ -161,7 +161,7 @@
@inline(__always) get {
String(_guts)._boundsCheck(position)
let i = _guts.scalarAlign(position)
- return _guts.errorCorrectedScalar(startingAt: i.encodedOffset).0
+ return _guts.errorCorrectedScalar(startingAt: i._encodedOffset).0
}
}
}
diff --git a/stdlib/public/core/Substring.swift b/stdlib/public/core/Substring.swift
index 33e3615..91b124d 100644
--- a/stdlib/public/core/Substring.swift
+++ b/stdlib/public/core/Substring.swift
@@ -132,7 +132,7 @@
let end = _slice.endIndex
_internalInvariant(start.transcodedOffset == 0 && end.transcodedOffset == 0)
- return Range(uncheckedBounds: (start.encodedOffset, end.encodedOffset))
+ return Range(uncheckedBounds: (start._encodedOffset, end._encodedOffset))
}
}
diff --git a/stdlib/public/core/UnicodeHelpers.swift b/stdlib/public/core/UnicodeHelpers.swift
index f57b52c..668c1ee 100644
--- a/stdlib/public/core/UnicodeHelpers.swift
+++ b/stdlib/public/core/UnicodeHelpers.swift
@@ -217,23 +217,23 @@
internal func scalarAlign(_ idx: Index) -> Index {
// TODO(String performance): isASCII check
- if _slowPath(idx.transcodedOffset != 0 || idx.encodedOffset == 0) {
+ if _slowPath(idx.transcodedOffset != 0 || idx._encodedOffset == 0) {
// Transcoded indices are already scalar aligned
- return String.Index(encodedOffset: idx.encodedOffset)
+ return String.Index(_encodedOffset: idx._encodedOffset)
}
if _slowPath(self.isForeign) {
return foreignScalarAlign(idx)
}
return self.withFastUTF8 { utf8 in
- let i = _scalarAlign(utf8, idx.encodedOffset)
+ let i = _scalarAlign(utf8, idx._encodedOffset)
// If no alignment is performed, keep grapheme cache
- if i == idx.encodedOffset {
+ if i == idx._encodedOffset {
return idx
}
- return Index(encodedOffset: i)
+ return Index(_encodedOffset: i)
}
}
@@ -277,7 +277,7 @@
if i == self.startIndex || i == self.endIndex { return true }
if _fastPath(isFastUTF8) {
- return self.withFastUTF8 { return !_isContinuation($0[i.encodedOffset]) }
+ return self.withFastUTF8 { return !_isContinuation($0[i._encodedOffset]) }
}
return i == foreignScalarAlign(i)
@@ -305,9 +305,9 @@
startingAt idx: String.Index
) -> (Unicode.Scalar, scalarLength: Int) {
_internalInvariant(idx.transcodedOffset == 0)
- _internalInvariant(idx.encodedOffset < self.count)
+ _internalInvariant(idx._encodedOffset < self.count)
- let start = idx.encodedOffset
+ let start = idx._encodedOffset
let leading = _getForeignCodeUnit(at: start)
if _fastPath(!_isSurrogate(leading)) {
@@ -338,10 +338,10 @@
endingAt idx: String.Index
) -> (Unicode.Scalar, scalarLength: Int) {
_internalInvariant(idx.transcodedOffset == 0)
- _internalInvariant(idx.encodedOffset <= self.count)
- _internalInvariant(idx.encodedOffset > 0)
+ _internalInvariant(idx._encodedOffset <= self.count)
+ _internalInvariant(idx._encodedOffset > 0)
- let end = idx.encodedOffset
+ let end = idx._encodedOffset
let trailing = _getForeignCodeUnit(at: end &- 1)
if _fastPath(!_isSurrogate(trailing)) {
return (Unicode.Scalar(_unchecked: UInt32(trailing)), 1)
@@ -371,9 +371,9 @@
at idx: String.Index
) -> UInt16 {
_internalInvariant(idx.transcodedOffset == 0)
- _internalInvariant(idx.encodedOffset < self.count)
+ _internalInvariant(idx._encodedOffset < self.count)
- let start = idx.encodedOffset
+ let start = idx._encodedOffset
let cu = _getForeignCodeUnit(at: start)
if _fastPath(!_isSurrogate(cu)) {
return cu
@@ -402,15 +402,15 @@
@usableFromInline @inline(never) // slow-path
@_effects(releasenone)
internal func foreignScalarAlign(_ idx: Index) -> Index {
- _internalInvariant(idx.encodedOffset < self.count)
+ _internalInvariant(idx._encodedOffset < self.count)
let ecCU = foreignErrorCorrectedUTF16CodeUnit(at: idx)
if _fastPath(!_isTrailingSurrogate(ecCU)) {
return idx
}
- _internalInvariant(idx.encodedOffset > 0,
+ _internalInvariant(idx._encodedOffset > 0,
"Error-correction shouldn't give trailing surrogate at position zero")
- return String.Index(encodedOffset: idx.encodedOffset &- 1)
+ return String.Index(_encodedOffset: idx._encodedOffset &- 1)
}
@usableFromInline @inline(never)
@@ -426,7 +426,7 @@
let count = end &- start
if start &- end == 1 {
return Character(String(self.foreignErrorCorrectedScalar(
- startingAt: String.Index(encodedOffset: start)
+ startingAt: String.Index(_encodedOffset: start)
).0))
}
@@ -459,7 +459,7 @@
return withFastUTF8 { _decodeScalar($0, startingAt: i) }
}
return foreignErrorCorrectedScalar(
- startingAt: String.Index(encodedOffset: i))
+ startingAt: String.Index(_encodedOffset: i))
}
@inlinable @inline(__always)
internal func errorCorrectedCharacter(
diff --git a/test/stdlib/StringIndex.swift b/test/stdlib/StringIndex.swift
index 925ef65..5332968 100644
--- a/test/stdlib/StringIndex.swift
+++ b/test/stdlib/StringIndex.swift
@@ -19,6 +19,7 @@
SimpleString.largeASCII.rawValue,
SimpleString.largeUnicode.rawValue,
SimpleString.emoji.rawValue,
+ "",
]
StringIndexTests.test("basic sanity checks") {
@@ -131,4 +132,76 @@
}
}
+StringIndexTests.test("UTF-16 Offsets") {
+ func validateOffsets(_ s: String) {
+ let end = s.endIndex
+ let utf16Count = s.utf16.count
+
+ expectEqual(end, String.Index(utf16Offset: utf16Count, in: s))
+ expectEqual(end, String.Index(utf16Offset: utf16Count, in: s[...]))
+
+ let pastEnd = String.Index(utf16Offset: utf16Count+1, in: s)
+
+ expectNotEqual(end, pastEnd)
+ expectEqual(pastEnd, String.Index(utf16Offset: utf16Count+1, in: s[...]))
+ expectEqual(pastEnd, String.Index(utf16Offset: utf16Count+2, in: s))
+ expectEqual(pastEnd, String.Index(utf16Offset: -1, in: s))
+ expectEqual(
+ pastEnd, String.Index(utf16Offset: Swift.max(1, utf16Count), in: s.dropFirst()))
+
+ let utf16Indices = Array(s.utf16.indices)
+ expectEqual(utf16Count, utf16Indices.count)
+ for i in 0..<utf16Indices.count {
+ let idx = String.Index(utf16Offset: i, in: s)
+ expectEqual(utf16Indices[i], idx)
+ expectEqual(i, idx.utf16Offset(in: s))
+ expectEqual(i, idx.utf16Offset(in: s[...]))
+
+ if i < s.dropLast().utf16.count {
+ expectEqual(
+ utf16Indices[i], String.Index(utf16Offset: i, in: s.dropLast()))
+ expectEqual(i, idx.utf16Offset(in: s.dropLast()))
+ } else if i == s.dropLast().utf16.count {
+ expectEqual(
+ utf16Indices[i], String.Index(utf16Offset: i, in: s.dropLast()))
+ } else {
+ expectNotEqual(
+ utf16Indices[i], String.Index(utf16Offset: i, in: s.dropLast()))
+ }
+ }
+ }
+
+ for s in simpleStrings {
+ validateOffsets(s)
+ }
+}
+
+func swift5ScalarAlign(_ idx: String.Index, in str: String) -> String.Index {
+ var idx = idx
+ while str.utf8[idx] & 0xC0 == 0x80 { str.utf8.formIndex(before: &idx) }
+ return idx
+}
+
+StringIndexTests.test("Scalar Align UTF-8 indices") {
+ // TODO: Test a new aligning API when we add it. For now, we
+ // test scalar-aligning UTF-8 indices
+
+ let str = "a😇"
+ let subScalarIdx = str.utf8.index(str.utf8.startIndex, offsetBy: 2)
+
+ let roundedIdx = swift5ScalarAlign(subScalarIdx, in: str)
+ expectEqual(1, roundedIdx.utf16Offset(in: str))
+
+ let roundedIdx2 = str.utf8[...subScalarIdx].lastIndex { $0 & 0xC0 != 0x80 }
+ expectEqual(roundedIdx, roundedIdx)
+
+ var roundedIdx3 = subScalarIdx
+ while roundedIdx3.samePosition(in: str.unicodeScalars) == nil {
+ str.utf8.formIndex(before: &roundedIdx3)
+ }
+ expectEqual(roundedIdx, roundedIdx3)
+}
+
+
+
runAllTests()
\ No newline at end of file
diff --git a/test/stdlib/StringTraps.swift b/test/stdlib/StringTraps.swift
index 729eea0..5d06ee7 100644
--- a/test/stdlib/StringTraps.swift
+++ b/test/stdlib/StringTraps.swift
@@ -168,5 +168,17 @@
_ = s8.utf8[i]
}
+StringTraps.test("String.Index.utf16Offset(in:)/subscalarUTF8")
+ .skip(.custom(
+ { _isFastAssertConfiguration() },
+ reason: "this trap is not guaranteed to happen in -Ounchecked"))
+ .code {
+ let s = "😇"
+ let u8 = s.utf8
+ let i = u8.index(after: u8.startIndex)
+ expectCrashLater()
+ _ = i.utf16Offset(in: s)
+}
+
runAllTests()
diff --git a/validation-test/stdlib/String.swift b/validation-test/stdlib/String.swift
index 8288959..3135d11 100644
--- a/validation-test/stdlib/String.swift
+++ b/validation-test/stdlib/String.swift
@@ -1365,8 +1365,8 @@
result, flags, stop
in
let r = result!.range(at: 1)
- let start = String.Index(encodedOffset: r.location)
- let end = String.Index(encodedOffset: r.location + r.length)
+ let start = String.Index(_encodedOffset: r.location)
+ let end = String.Index(_encodedOffset: r.location + r.length)
matches.append(String(s.utf16[start..<end])!)
}