Skip to content

Commit 3002efa

Browse files
committed
[stdlib] String.UTF16View: Align indices before calling default algorithms
[Bidirectional]Collection’s default index manipulation methods (as well as _utf16Distance) do not expect to be given unreachable indices, and they tend to fail when operating on them. Round indices down to the nearest scalar boundary before calling these. (cherry picked from commit e46f8f8)
1 parent 27c4e0c commit 3002efa

File tree

1 file changed

+27
-15
lines changed

1 file changed

+27
-15
lines changed

stdlib/public/core/StringUTF16View.swift

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -197,47 +197,57 @@ extension String.UTF16View: BidirectionalCollection {
197197
return idx.encoded(offsetBy: -len)._scalarAligned._knownUTF8
198198
}
199199

200+
@_effects(releasenone)
200201
public func index(_ i: Index, offsetBy n: Int) -> Index {
201-
let i = _guts.ensureMatchingEncoding(i)
202+
var i = _guts.ensureMatchingEncoding(i)
202203
_precondition(i <= endIndex, "String index is out of bounds")
204+
203205
if _slowPath(_guts.isForeign) {
204206
return _foreignIndex(i, offsetBy: n)
205207
}
206208

207-
if !_guts.isASCII { // We have ASCII fast paths below
208-
let threshold = (
209-
i == startIndex ? _breadcrumbStride / 2 : _breadcrumbStride)
210-
if n.magnitude < threshold {
211-
// Do not use breadcrumbs if directly computing the result is expected to
212-
// be cheaper.
213-
return _index(i, offsetBy: n)._knownUTF8
214-
}
209+
if _guts.isASCII {
210+
return Index(
211+
_encodedOffset: i._encodedOffset + n
212+
)._scalarAligned._encodingIndependent
213+
}
214+
215+
i = _utf16AlignNativeIndex(i)
216+
let threshold = (
217+
i == startIndex ? _breadcrumbStride / 2 : _breadcrumbStride)
218+
if n.magnitude < threshold {
219+
// Do not use breadcrumbs if directly computing the result is expected
220+
// to be cheaper.
221+
return _index(i, offsetBy: n)._knownUTF8
215222
}
216223

217224
let lowerOffset = _nativeGetOffset(for: i)
218225
let result = _nativeGetIndex(for: lowerOffset + n)
219226
return result
220227
}
221228

229+
@_effects(releasenone)
222230
public func index(
223231
_ i: Index, offsetBy n: Int, limitedBy limit: Index
224232
) -> Index? {
225-
let limit = _guts.ensureMatchingEncoding(limit)
233+
var limit = _guts.ensureMatchingEncoding(limit)
226234
guard _fastPath(limit <= endIndex) else { return index(i, offsetBy: n) }
227235

228-
let i = _guts.ensureMatchingEncoding(i)
236+
var i = _guts.ensureMatchingEncoding(i)
229237
_precondition(i <= endIndex, "String index is out of bounds")
230238

231239
if _slowPath(_guts.isForeign) {
232240
return _foreignIndex(i, offsetBy: n, limitedBy: limit)
233241
}
234242

235243
if !_guts.isASCII { // We have ASCII fast paths below
244+
limit = _utf16AlignNativeIndex(limit)
245+
i = _utf16AlignNativeIndex(i)
236246
let threshold = (
237247
_breadcrumbStride + (i == startIndex ? 0 : _breadcrumbStride / 2))
238248
if n.magnitude < threshold {
239-
// Do not use breadcrumbs if directly computing the result is expected to
240-
// be cheaper.
249+
// Do not use breadcrumbs if directly computing the result is expected
250+
// to be cheaper.
241251
return _index(i, offsetBy: n, limitedBy: limit)?._knownUTF8
242252
}
243253
}
@@ -351,8 +361,8 @@ extension String.UTF16View: BidirectionalCollection {
351361
for range: Range<Index>,
352362
from start: Index
353363
) -> Range<Int> {
354-
let lower = _guts.ensureMatchingEncoding(range.lowerBound)
355-
let upper = _guts.ensureMatchingEncoding(range.upperBound)
364+
var lower = _guts.ensureMatchingEncoding(range.lowerBound)
365+
var upper = _guts.ensureMatchingEncoding(range.upperBound)
356366
_internalInvariant(_guts.hasMatchingEncoding(start))
357367

358368
_precondition(
@@ -378,6 +388,8 @@ extension String.UTF16View: BidirectionalCollection {
378388
}
379389

380390
if utf8Distance.magnitude <= _breadcrumbStride / 2 {
391+
lower = _utf16AlignNativeIndex(lower)
392+
upper = _utf16AlignNativeIndex(upper)
381393
let lowerOffset = distance(from: start, to: lower)
382394
let distance = _utf16Distance(from: lower, to: upper)
383395
return Range(uncheckedBounds: (lowerOffset, lowerOffset + distance))

0 commit comments

Comments
 (0)