@@ -186,8 +186,8 @@ extension String.UTF16View: BidirectionalCollection {
186
186
return _foreignIndex ( i, offsetBy: n)
187
187
}
188
188
189
- let lowerOffset = _getOffset ( for: i)
190
- let result = _getIndex ( for: lowerOffset + n)
189
+ let lowerOffset = _nativeGetOffset ( for: i)
190
+ let result = _nativeGetIndex ( for: lowerOffset + n)
191
191
return result
192
192
}
193
193
@@ -199,8 +199,8 @@ extension String.UTF16View: BidirectionalCollection {
199
199
return _foreignIndex ( i, offsetBy: n, limitedBy: limit)
200
200
}
201
201
202
- let iOffset = _getOffset ( for: i)
203
- let limitOffset = _getOffset ( for: limit)
202
+ let iOffset = _nativeGetOffset ( for: i)
203
+ let limitOffset = _nativeGetOffset ( for: limit)
204
204
205
205
// If distance < 0, limit has no effect if it is greater than i.
206
206
if _slowPath ( n < 0 && limit <= i && limitOffset > iOffset + n) {
@@ -211,7 +211,7 @@ extension String.UTF16View: BidirectionalCollection {
211
211
return nil
212
212
}
213
213
214
- let result = _getIndex ( for: iOffset + n)
214
+ let result = _nativeGetIndex ( for: iOffset + n)
215
215
return result
216
216
}
217
217
@@ -221,8 +221,8 @@ extension String.UTF16View: BidirectionalCollection {
221
221
return _foreignDistance ( from: start, to: end)
222
222
}
223
223
224
- let lower = _getOffset ( for: start)
225
- let upper = _getOffset ( for: end)
224
+ let lower = _nativeGetOffset ( for: start)
225
+ let upper = _nativeGetOffset ( for: end)
226
226
return upper &- lower
227
227
}
228
228
@@ -231,7 +231,7 @@ extension String.UTF16View: BidirectionalCollection {
231
231
if _slowPath ( _guts. isForeign) {
232
232
return _foreignCount ( )
233
233
}
234
- return _getOffset ( for: endIndex)
234
+ return _nativeGetOffset ( for: endIndex)
235
235
}
236
236
237
237
/// Accesses the code unit at the given position.
@@ -458,7 +458,7 @@ extension String.UTF16View {
458
458
459
459
@usableFromInline
460
460
@_effects ( releasenone)
461
- internal func _getOffset ( for idx: Index ) -> Int {
461
+ internal func _nativeGetOffset ( for idx: Index ) -> Int {
462
462
// Trivial and common: start
463
463
if idx == startIndex { return 0 }
464
464
@@ -478,7 +478,7 @@ extension String.UTF16View {
478
478
479
479
@usableFromInline
480
480
@_effects ( releasenone)
481
- internal func _getIndex ( for offset: Int ) -> Index {
481
+ internal func _nativeGetIndex ( for offset: Int ) -> Index {
482
482
// Trivial and common: start
483
483
if offset == 0 { return startIndex }
484
484
@@ -493,7 +493,40 @@ extension String.UTF16View {
493
493
// Otherwise, find the nearest lower-bound breadcrumb and advance that
494
494
let ( crumb, remaining) = breadcrumbsPtr. pointee. getBreadcrumb (
495
495
forOffset: offset)
496
- return _index ( crumb, offsetBy: remaining)
496
+ if remaining == 0 { return crumb }
497
+
498
+ return _guts. withFastUTF8 { utf8 in
499
+ var readIdx = crumb. encodedOffset
500
+ var readEnd = utf8. count
501
+ _sanityCheck ( readIdx < readEnd)
502
+
503
+ var utf16I = 0
504
+ let utf16End : Int = remaining
505
+
506
+ // Adjust for sub-scalar initial transcoding: If we're starting the scan
507
+ // at a trailing surrogate, then we set our starting count to be -1 so as
508
+ // offset counting the leading surrogate.
509
+ if crumb. transcodedOffset != 0 {
510
+ utf16I = - 1
511
+ }
512
+
513
+ while true {
514
+ let len = _utf8ScalarLength ( utf8 [ readIdx] )
515
+ let utf16Len = len == 4 ? 2 : 1
516
+ utf16I &+= utf16Len
517
+
518
+ if utf16I >= utf16End {
519
+ // Uncommon: final sub-scalar transcoded offset
520
+ if _slowPath ( utf16I > utf16End) {
521
+ _sanityCheck ( utf16Len == 2 )
522
+ return Index ( encodedOffset: readIdx, transcodedOffset: 1 )
523
+ }
524
+ return Index ( encodedOffset: readIdx &+ len)
525
+ }
526
+
527
+ readIdx &+= len
528
+ }
529
+ }
497
530
}
498
531
}
499
532
0 commit comments