Skip to content

Commit 514228a

Browse files
committed
WIP: More directions in place
1 parent 1b240d5 commit 514228a

File tree

2 files changed

+45
-14
lines changed

2 files changed

+45
-14
lines changed

stdlib/public/core/StringUTF8View.swift

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ extension String.UTF8View {
448448
}
449449

450450
let (scalar, scalarLen) = _guts.foreignErrorCorrectedScalar(
451-
endingAt: idx)
451+
endingAt: idx.strippingTranscoding)
452452
let utf8Len = UTF8.width(scalar)
453453
return idx.encoded(
454454
offsetBy: -scalarLen
@@ -457,19 +457,18 @@ extension String.UTF8View {
457457

458458
@usableFromInline @inline(never)
459459
@_effects(releasenone)
460-
internal func _foreignSubscript(position i: Index) -> UTF8.CodeUnit {
460+
internal func _foreignSubscript(position idx: Index) -> UTF8.CodeUnit {
461461
_internalInvariant(_guts.isForeign)
462462

463-
// FIXME: We should need some kind of alignment if given an index into a
464-
// surrogate pair
463+
let idx = _utf8AlignForeignIndex(idx)
465464

466465
let scalar = _guts.foreignErrorCorrectedScalar(
467-
startingAt: _guts.scalarAlign(i)).0
466+
startingAt: idx.strippingTranscoding).0
468467
let encoded = Unicode.UTF8.encode(scalar)._unsafelyUnwrappedUnchecked
469-
_internalInvariant(i.transcodedOffset < 1+encoded.count)
468+
_internalInvariant(idx.transcodedOffset < 1+encoded.count)
470469

471470
return encoded[
472-
encoded.index(encoded.startIndex, offsetBy: i.transcodedOffset)]
471+
encoded.index(encoded.startIndex, offsetBy: idx.transcodedOffset)]
473472
}
474473

475474
@usableFromInline @inline(never)
@@ -492,24 +491,27 @@ extension String.UTF8View {
492491
@_effects(releasenone)
493492
internal func _foreignDistance(from i: Index, to j: Index) -> Int {
494493
_internalInvariant(_guts.isForeign)
495-
494+
495+
let i = _utf8AlignForeignIndex(i)
496+
let j = _utf8AlignForeignIndex(j)
497+
498+
496499
#if _runtime(_ObjC)
497-
// Currently, foreign means NSString
500+
// Currently, foreign means NSString
498501
if let count = _cocoaStringUTF8Count(
499502
_guts._object.cocoaObject,
500503
range: i._encodedOffset ..< j._encodedOffset
501504
) {
502-
//_cocoaStringUTF8Count gave us the scalar aligned count, but we still
503-
//need to compensate for sub-scalar indexing, e.g. if `i` is in the middle
504-
//of a two-byte UTF8 scalar.
505+
// _cocoaStringUTF8Count gave us the scalar aligned count, but we still
506+
// need to compensate for sub-scalar indexing, e.g. if `i` is in the
507+
// middle of a two-byte UTF8 scalar.
505508
let refinedCount = count - (i.transcodedOffset + j.transcodedOffset)
506509
_internalInvariant(refinedCount == _distance(from: i, to: j))
507510
return refinedCount
508511
}
509512
#endif
510513

511514
return _distance(from: i, to: j)
512-
513515
}
514516

515517
@usableFromInline @inline(never)

test/stdlib/StringIndex.swift

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,26 @@ StringIndexTests.test("Index interchange") {
376376
expect(curSubChar == str[curUTF8Idx])
377377
expect(!UTF16.isTrailSurrogate(str.utf16[curUTF8Idx]))
378378
expect(utf8StartIdx == str[curUTF8Idx...].startIndex)
379+
expect(str[utf8StartIdx..<curUTF8Idx].isEmpty)
379380
expect(0 == str.utf16.distance(from: utf8StartIdx, to: curUTF8Idx))
380381

381382
str.utf8.formIndex(after: &curUTF8Idx)
382383
}
383384
expect(curUTF8Idx == curScalarIdx)
384385

386+
var utf8RevIdx = curUTF8Idx
387+
while utf8RevIdx > utf8StartIdx {
388+
str.utf8.formIndex(before: &utf8RevIdx)
389+
390+
expect(curScalar == str.unicodeScalars[utf8RevIdx])
391+
expect(curSubChar == str[utf8RevIdx])
392+
expect(!UTF16.isTrailSurrogate(str.utf16[utf8RevIdx]))
393+
expect(utf8StartIdx == str[utf8RevIdx...].startIndex)
394+
expect(str[utf8StartIdx..<utf8RevIdx].isEmpty)
395+
expect(0 == str.utf16.distance(from: utf8StartIdx, to: utf8RevIdx))
396+
}
397+
expect(utf8RevIdx == utf8StartIdx)
398+
385399
let utf16StartIdx = curUTF16Idx
386400
defer {
387401
let sub = str.unicodeScalars[utf16StartIdx..<curUTF16Idx]
@@ -398,11 +412,26 @@ StringIndexTests.test("Index interchange") {
398412
expect(curSubChar == str[curUTF16Idx])
399413
expect(!UTF8.isContinuation(str.utf8[curUTF16Idx]))
400414
expect(utf16StartIdx == str[curUTF16Idx...].startIndex)
401-
// expect(0 == str.utf8.distance(from: utf16StartIdx, to: curUTF16Idx))
415+
expect(str[utf16StartIdx..<curUTF16Idx].isEmpty)
416+
expect(0 == str.utf8.distance(from: utf16StartIdx, to: curUTF16Idx))
402417

403418
str.utf16.formIndex(after: &curUTF16Idx)
404419
}
405420
expect(curUTF16Idx == curScalarIdx)
421+
422+
var utf16RevIdx = curUTF16Idx
423+
while utf16RevIdx > utf16StartIdx {
424+
str.utf16.formIndex(before: &utf16RevIdx)
425+
426+
expect(curScalar == str.unicodeScalars[utf16RevIdx])
427+
expect(curSubChar == str[utf16RevIdx])
428+
expect(!UTF8.isContinuation(str.utf8[utf16RevIdx]))
429+
expect(utf16StartIdx == str[utf16RevIdx...].startIndex)
430+
expect(str[utf16StartIdx..<utf16RevIdx].isEmpty)
431+
expect(0 == str.utf8.distance(from: utf16StartIdx, to: utf16RevIdx))
432+
}
433+
expect(utf16RevIdx == utf16StartIdx)
434+
406435
}
407436
}
408437
}

0 commit comments

Comments
 (0)