Skip to content

Commit a088e13

Browse files
committed
[String] Add UTF-8 fast-paths for Foundation initializers
Many Foundation initializers could benefit from faster string construction and subsequent reads in Swift 5. Add UTF-8 fast paths for when constructing a string from a valid UTF-8 code units.
1 parent a628d5d commit a088e13

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

stdlib/public/Darwin/Foundation/NSStringAPI.swift

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,10 @@ extension String {
178178
/// Creates a string by copying the data from a given
179179
/// C array of UTF8-encoded bytes.
180180
public init?(utf8String bytes: UnsafePointer<CChar>) {
181+
if let str = String(validatingUTF8: bytes) {
182+
self = str
183+
return
184+
}
181185
if let ns = NSString(utf8String: bytes) {
182186
self = String._unconditionallyBridgeFromObjectiveC(ns)
183187
} else {
@@ -202,12 +206,18 @@ extension String {
202206
/// - Parameters:
203207
/// - bytes: A sequence of bytes to interpret using `encoding`.
204208
/// - encoding: The ecoding to use to interpret `bytes`.
205-
public init? <S: Sequence>(bytes: __shared S, encoding: Encoding)
206-
where S.Iterator.Element == UInt8 {
209+
public init?<S: Sequence>(bytes: __shared S, encoding: Encoding)
210+
where S.Iterator.Element == UInt8 {
207211
let byteArray = Array(bytes)
212+
if encoding == .utf8,
213+
let str = byteArray.withUnsafeBufferPointer({ String._tryFromUTF8($0) })
214+
{
215+
self = str
216+
return
217+
}
218+
208219
if let ns = NSString(
209220
bytes: byteArray, length: byteArray.count, encoding: encoding.rawValue) {
210-
211221
self = String._unconditionallyBridgeFromObjectiveC(ns)
212222
} else {
213223
return nil
@@ -365,6 +375,10 @@ extension String {
365375
cString: UnsafePointer<CChar>,
366376
encoding enc: Encoding
367377
) {
378+
if enc == .utf8, let str = String(validatingUTF8: cString) {
379+
self = str
380+
return
381+
}
368382
if let ns = NSString(cString: cString, encoding: enc.rawValue) {
369383
self = String._unconditionallyBridgeFromObjectiveC(ns)
370384
} else {
@@ -381,6 +395,14 @@ extension String {
381395
/// Returns a `String` initialized by converting given `data` into
382396
/// Unicode characters using a given `encoding`.
383397
public init?(data: __shared Data, encoding: Encoding) {
398+
if encoding == .utf8,
399+
let str = data.withUnsafeBytes({
400+
String._tryFromUTF8($0.bindMemory(to: UInt8.self))
401+
}) {
402+
self = str
403+
return
404+
}
405+
384406
guard let s = NSString(data: data, encoding: encoding.rawValue) else { return nil }
385407
self = String._unconditionallyBridgeFromObjectiveC(s)
386408
}

stdlib/public/core/StringCreate.swift

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,10 @@ extension String {
4242
return storage.asString
4343
}
4444

45-
@usableFromInline
46-
internal static func _tryFromUTF8(
47-
_ input: UnsafeBufferPointer<UInt8>
48-
) -> String? {
45+
public // SPI(Foundation)
46+
static func _tryFromUTF8(_ input: UnsafeBufferPointer<UInt8>) -> String? {
4947
guard case .success(let extraInfo) = validateUTF8(input) else {
50-
return nil
48+
return nil
5149
}
5250

5351
return String._uncheckedFromUTF8(input, isASCII: extraInfo.isASCII)

0 commit comments

Comments
 (0)