@@ -117,7 +117,8 @@ extension String.UTF16View {
117
117
#else
118
118
@usableFromInline @inline ( never) @_effects ( releasenone)
119
119
internal func _invariantCheck( ) {
120
- // TODO: Ensure start/end are not sub-scalr UTF-8 transcoded indices
120
+ _internalInvariant (
121
+ startIndex. transcodedOffset == 0 && endIndex. transcodedOffset == 0 )
121
122
}
122
123
#endif // INTERNAL_CHECKS_ENABLED
123
124
}
@@ -143,9 +144,8 @@ extension String.UTF16View: BidirectionalCollection {
143
144
144
145
@inlinable @inline ( __always)
145
146
public func index( after i: Index ) -> Index {
146
- // TODO(String performance) known-ASCII fast path
147
-
148
147
if _slowPath ( _guts. isForeign) { return _foreignIndex ( after: i) }
148
+ if _guts. isASCII { return i. nextEncoded }
149
149
150
150
// For a BMP scalar (1-3 UTF-8 code units), advance past it. For a non-BMP
151
151
// scalar, use a transcoded offset first.
@@ -159,9 +159,8 @@ extension String.UTF16View: BidirectionalCollection {
159
159
@inlinable @inline ( __always)
160
160
public func index( before i: Index ) -> Index {
161
161
precondition ( !i. isZeroPosition)
162
- // TODO(String performance) known-ASCII fast path
163
-
164
162
if _slowPath ( _guts. isForeign) { return _foreignIndex ( before: i) }
163
+ if _guts. isASCII { return i. priorEncoded }
165
164
166
165
if i. transcodedOffset != 0 {
167
166
_internalInvariant ( i. transcodedOffset == 1 )
@@ -181,8 +180,6 @@ extension String.UTF16View: BidirectionalCollection {
181
180
}
182
181
183
182
public func index( _ i: Index , offsetBy n: Int ) -> Index {
184
- // TODO(String performance) known-ASCII fast path
185
-
186
183
if _slowPath ( _guts. isForeign) {
187
184
return _foreignIndex ( i, offsetBy: n)
188
185
}
@@ -195,7 +192,6 @@ extension String.UTF16View: BidirectionalCollection {
195
192
public func index(
196
193
_ i: Index , offsetBy n: Int , limitedBy limit: Index
197
194
) -> Index ? {
198
- // TODO(String performance) known-ASCII fast path
199
195
if _slowPath ( _guts. isForeign) {
200
196
return _foreignIndex ( i, offsetBy: n, limitedBy: limit)
201
197
}
@@ -217,7 +213,6 @@ extension String.UTF16View: BidirectionalCollection {
217
213
}
218
214
219
215
public func distance( from start: Index , to end: Index ) -> Int {
220
- // TODO(String performance) known-ASCII fast path
221
216
if _slowPath ( _guts. isForeign) {
222
217
return _foreignDistance ( from: start, to: end)
223
218
}
@@ -250,7 +245,6 @@ extension String.UTF16View: BidirectionalCollection {
250
245
@inlinable
251
246
public subscript( i: Index ) -> UTF16 . CodeUnit {
252
247
@inline ( __always) get {
253
- // TODO(String performance) known-ASCII fast path
254
248
String ( _guts) . _boundsCheck ( i)
255
249
256
250
if _fastPath ( _guts. isFastUTF8) {
@@ -267,16 +261,16 @@ extension String.UTF16View: BidirectionalCollection {
267
261
}
268
262
}
269
263
extension String . UTF16View : CustomStringConvertible {
270
- @inlinable
271
- public var description : String {
272
- @inline ( __always) get { return String ( _guts) }
273
- }
264
+ @inlinable
265
+ public var description : String {
266
+ @inline ( __always) get { return String ( _guts) }
267
+ }
274
268
}
275
269
276
270
extension String . UTF16View : CustomDebugStringConvertible {
277
- public var debugDescription : String {
278
- return " StringUTF16( \( self . description. debugDescription) ) "
279
- }
271
+ public var debugDescription : String {
272
+ return " StringUTF16( \( self . description. debugDescription) ) "
273
+ }
280
274
}
281
275
282
276
extension String {
@@ -462,8 +456,11 @@ extension String.UTF16View {
462
456
// Trivial and common: start
463
457
if idx == startIndex { return 0 }
464
458
465
- if _guts. isASCII { return idx. encodedOffset }
466
-
459
+ if _guts. isASCII {
460
+ _internalInvariant ( idx. transcodedOffset == 0 )
461
+ return idx. encodedOffset
462
+ }
463
+
467
464
if idx. encodedOffset < _shortHeuristic || !_guts. hasBreadcrumbs {
468
465
return _distance ( from: startIndex, to: idx)
469
466
}
@@ -483,7 +480,9 @@ extension String.UTF16View {
483
480
internal func _nativeGetIndex( for offset: Int ) -> Index {
484
481
// Trivial and common: start
485
482
if offset == 0 { return startIndex }
486
-
483
+
484
+ if _guts. isASCII { return Index ( encodedOffset: offset) }
485
+
487
486
if offset < _shortHeuristic || !_guts. hasBreadcrumbs {
488
487
return _index ( startIndex, offsetBy: offset)
489
488
}
@@ -542,12 +541,26 @@ extension String {
542
541
543
542
if _slowPath ( range. isEmpty) { return }
544
543
544
+ let isASCII = _guts. isASCII
545
545
return _guts. withFastUTF8 { utf8 in
546
546
var writeIdx = 0
547
547
let writeEnd = buffer. count
548
548
var readIdx = range. lowerBound. encodedOffset
549
549
let readEnd = range. upperBound. encodedOffset
550
550
551
+ if isASCII {
552
+ _internalInvariant ( range. lowerBound. transcodedOffset == 0 )
553
+ _internalInvariant ( range. upperBound. transcodedOffset == 0 )
554
+ while readIdx < readEnd {
555
+ _internalInvariant ( utf8 [ readIdx] < 0x80 )
556
+ buffer [ _unchecked: writeIdx] = UInt16 (
557
+ truncatingIfNeeded: utf8 [ _unchecked: readIdx] )
558
+ readIdx &+= 1
559
+ writeIdx &+= 1
560
+ }
561
+ return
562
+ }
563
+
551
564
// Handle mid-transcoded-scalar initial index
552
565
if _slowPath ( range. lowerBound. transcodedOffset != 0 ) {
553
566
_internalInvariant ( range. lowerBound. transcodedOffset == 1 )
0 commit comments