@@ -398,49 +398,61 @@ extension String.UTF8View {
398
398
399
399
// Foreign string support
400
400
extension String . UTF8View {
401
+ // Align a foreign UTF-16 index to a valid UTF-8 position. If there is a
402
+ // transcoded offset already, this is already a valid UTF-8 position
403
+ // (referring to a continuation byte) and returns `idx`. Otherwise, this will
404
+ // scalar-align the index. This is needed because we may be passed a
405
+ // non-scalar-aligned foreign index from the UTF16View.
406
+ @inline ( __always)
407
+ internal func _utf8AlignForeignIndex( _ idx: String . Index ) -> String . Index {
408
+ _internalInvariant ( _guts. isForeign)
409
+ guard idx. transcodedOffset == 0 else { return idx }
410
+ return _guts. scalarAlign ( idx)
411
+ }
412
+
401
413
@usableFromInline @inline ( never)
402
414
@_effects ( releasenone)
403
- internal func _foreignIndex( after i : Index ) -> Index {
415
+ internal func _foreignIndex( after idx : Index ) -> Index {
404
416
_internalInvariant ( _guts. isForeign)
405
417
406
- // FIXME: We should need some kind of alignment if given an index into a
407
- // surrogate pair
418
+ let idx = _utf8AlignForeignIndex ( idx)
408
419
409
420
let ( scalar, scalarLen) = _guts. foreignErrorCorrectedScalar (
410
- startingAt: i . strippingTranscoding)
421
+ startingAt: idx . strippingTranscoding)
411
422
let utf8Len = UTF8 . width ( scalar)
412
423
413
424
if utf8Len == 1 {
414
- _internalInvariant ( i . transcodedOffset == 0 )
415
- return i . nextEncoded
425
+ _internalInvariant ( idx . transcodedOffset == 0 )
426
+ return idx . nextEncoded
416
427
}
417
428
418
429
// Check if we're still transcoding sub-scalar
419
- if i . transcodedOffset < utf8Len - 1 {
420
- return i . nextTranscoded
430
+ if idx . transcodedOffset < utf8Len - 1 {
431
+ return idx . nextTranscoded
421
432
}
422
433
423
434
// Skip to the next scalar
424
- return i . encoded ( offsetBy: scalarLen)
435
+ return idx . encoded ( offsetBy: scalarLen)
425
436
}
426
437
427
438
@usableFromInline @inline ( never)
428
439
@_effects ( releasenone)
429
- internal func _foreignIndex( before i : Index ) -> Index {
440
+ internal func _foreignIndex( before idx : Index ) -> Index {
430
441
_internalInvariant ( _guts. isForeign)
431
442
432
- // FIXME: We should need some kind of alignment if given an index into a
433
- // surrogate pair
443
+ let idx = _utf8AlignForeignIndex ( idx)
434
444
435
- if i . transcodedOffset != 0 {
436
- _internalInvariant ( ( 1 ... 3 ) ~= i . transcodedOffset)
437
- return i . priorTranscoded
445
+ if idx . transcodedOffset != 0 {
446
+ _internalInvariant ( ( 1 ... 3 ) ~= idx . transcodedOffset)
447
+ return idx . priorTranscoded
438
448
}
439
449
440
450
let ( scalar, scalarLen) = _guts. foreignErrorCorrectedScalar (
441
- endingAt: i )
451
+ endingAt: idx )
442
452
let utf8Len = UTF8 . width ( scalar)
443
- return i. encoded ( offsetBy: - scalarLen) . transcoded ( withOffset: utf8Len &- 1 )
453
+ return idx. encoded (
454
+ offsetBy: - scalarLen
455
+ ) . transcoded ( withOffset: utf8Len &- 1 )
444
456
}
445
457
446
458
@usableFromInline @inline ( never)
0 commit comments