@@ -196,9 +196,30 @@ extension _StringGuts {
196
196
/// inconsistent with `_opaqueCharacterStride(endingAt:)`. On the other hand,
197
197
/// this behavior makes this suitable for use in substrings whose start index
198
198
/// itself does not fall on a cluster boundary.
199
- @usableFromInline @inline ( never )
199
+ @usableFromInline @inline ( __always )
200
200
@_effects ( releasenone)
201
201
internal func _opaqueCharacterStride( startingAt i: Int ) -> Int {
202
+ _internalInvariant ( i < endIndex. _encodedOffset)
203
+ if isFastUTF8 {
204
+ let fast = withFastUTF8 { utf8 in
205
+ if i &+ 1 == utf8. count { return true }
206
+ let pair = UnsafeRawPointer (
207
+ utf8. baseAddress. unsafelyUnwrapped
208
+ ) . loadUnaligned ( fromByteOffset: i, as: UInt16 . self)
209
+ //& 0x8080 == 0 is "both not ASCII", != 0x0A0D is "not CRLF"
210
+ return pair & 0x8080 == 0 && pair != 0x0A0D
211
+ }
212
+ if _fastPath ( fast) {
213
+ _internalInvariant ( _opaqueComplexCharacterStride ( startingAt: i) == 1 )
214
+ return 1
215
+ }
216
+ }
217
+
218
+ return _opaqueComplexCharacterStride ( startingAt: i)
219
+ }
220
+
221
+ @_effects ( releasenone) @inline ( never)
222
+ internal func _opaqueComplexCharacterStride( startingAt i: Int ) -> Int {
202
223
if _slowPath ( isForeign) {
203
224
return _foreignOpaqueCharacterStride ( startingAt: i)
204
225
}
@@ -221,9 +242,32 @@ extension _StringGuts {
221
242
///
222
243
/// Note: unlike `_opaqueCharacterStride(startingAt:)`, this method always
223
244
/// finds a correct grapheme cluster boundary.
224
- @usableFromInline @inline ( never)
245
+
246
+ @usableFromInline @inline ( __always)
225
247
@_effects ( releasenone)
226
248
internal func _opaqueCharacterStride( endingAt i: Int ) -> Int {
249
+ if i <= 1 {
250
+ return i
251
+ }
252
+ if isFastUTF8 {
253
+ let fast = withFastUTF8 { utf8 in
254
+ let pair = UnsafeRawPointer (
255
+ utf8. baseAddress. unsafelyUnwrapped
256
+ ) . loadUnaligned ( fromByteOffset: i &- 2 , as: UInt16 . self)
257
+ //& 0x8080 == 0 is "both not ASCII", != 0x0A0D is "not CRLF"
258
+ return pair & 0x8080 == 0 && pair != 0x0A0D
259
+ }
260
+ if _fastPath ( fast) {
261
+ _internalInvariant ( _opaqueComplexCharacterStride ( endingAt: i) == 1 )
262
+ return 1
263
+ }
264
+ }
265
+
266
+ return _opaqueComplexCharacterStride ( endingAt: i)
267
+ }
268
+
269
+ @_effects ( releasenone) @inline ( never)
270
+ internal func _opaqueComplexCharacterStride( endingAt i: Int ) -> Int {
227
271
if _slowPath ( isForeign) {
228
272
return _foreignOpaqueCharacterStride ( endingAt: i)
229
273
}
0 commit comments