Skip to content

Commit 60fff84

Browse files
lorenteymilseman
authored andcommitted
_StringGuts, _StringVariant: Add unicodeScalar(startingAt:), unicodeScalar(endingAt:)
1 parent 99b21ef commit 60fff84

File tree

2 files changed

+46
-12
lines changed

2 files changed

+46
-12
lines changed

stdlib/public/core/StringUnicodeScalarView.swift

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -175,17 +175,7 @@ extension String {
175175
@_inlineable // FIXME(sil-serialize-all)
176176
public subscript(position: Index) -> Unicode.Scalar {
177177
let offset = position.encodedOffset
178-
if _slowPath(_guts._isOpaque) {
179-
let opaque = _guts._asOpaque()
180-
return opaque.decodeUnicodeScalar(startingAt: offset)
181-
} else if _guts.isASCII {
182-
let ascii = _guts._unmanagedASCIIView
183-
let u = ascii.codeUnit(atCheckedOffset: offset)
184-
return Unicode.Scalar(_unchecked: UInt32(u))
185-
} else {
186-
let utf16 = _guts._unmanagedUTF16View
187-
return utf16.decodeUnicodeScalar(startingAt: offset)
188-
}
178+
return _guts.unicodeScalar(startingAt: offset)
189179
}
190180

191181
/// An iterator over the Unicode scalars that make up a `UnicodeScalarView`
@@ -281,6 +271,34 @@ extension String {
281271
public typealias UnicodeScalarIndex = UnicodeScalarView.Index
282272
}
283273

274+
extension _StringGuts {
275+
@_inlineable
276+
@_versioned
277+
internal func unicodeScalar(startingAt offset: Int) -> Unicode.Scalar {
278+
if _slowPath(_isOpaque) {
279+
return _asOpaque().unicodeScalar(startingAt: offset)
280+
}
281+
if isASCII {
282+
let u = _unmanagedASCIIView.codeUnit(atCheckedOffset: offset)
283+
return Unicode.Scalar(_unchecked: UInt32(u))
284+
}
285+
return _unmanagedUTF16View.unicodeScalar(startingAt: offset)
286+
}
287+
288+
@_inlineable
289+
@_versioned
290+
internal func unicodeScalar(endingAt offset: Int) -> Unicode.Scalar {
291+
if _slowPath(_isOpaque) {
292+
return _asOpaque().unicodeScalar(endingAt: offset)
293+
}
294+
if isASCII {
295+
let u = _unmanagedASCIIView.codeUnit(atCheckedOffset: offset - 1)
296+
return Unicode.Scalar(_unchecked: UInt32(u))
297+
}
298+
return _unmanagedUTF16View.unicodeScalar(endingAt: offset)
299+
}
300+
}
301+
284302
extension String.UnicodeScalarView : _SwiftStringView {
285303
@_inlineable // FIXME(sil-serialize-all)
286304
@_versioned // FIXME(sil-serialize-all)

stdlib/public/core/StringVariant.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ extension _StringVariant {
166166

167167
@_inlineable
168168
@_versioned
169-
func decodeUnicodeScalar(startingAt offset: Int) -> Unicode.Scalar {
169+
func unicodeScalar(startingAt offset: Int) -> Unicode.Scalar {
170170
let u0 = self.codeUnit(atCheckedOffset: offset)
171171
if _fastPath(UTF16._isScalar(u0)) {
172172
return Unicode.Scalar(_unchecked: UInt32(u0))
@@ -179,4 +179,20 @@ extension _StringVariant {
179179
}
180180
return Unicode.Scalar._replacementCharacter
181181
}
182+
183+
@_inlineable
184+
@_versioned
185+
func unicodeScalar(endingAt offset: Int) -> Unicode.Scalar {
186+
let u1 = self.codeUnit(atCheckedOffset: offset - 1)
187+
if _fastPath(UTF16._isScalar(u1)) {
188+
return Unicode.Scalar(_unchecked: UInt32(u1))
189+
}
190+
if UTF16.isTrailSurrogate(u1) && offset >= 2 {
191+
let u0 = self[offset - 2]
192+
if UTF16.isLeadSurrogate(u0) {
193+
return UTF16._decodeSurrogates(u0, u1)
194+
}
195+
}
196+
return Unicode.Scalar._replacementCharacter
197+
}
182198
}

0 commit comments

Comments
 (0)