Add fast paths for String(decoding:…, as: Unicode.ASCII.self)

This commit is contained in:
David Smith
2019-10-14 14:08:10 -07:00
parent 965d7c7b18
commit 007ff00617
2 changed files with 64 additions and 9 deletions

View File

@@ -50,12 +50,10 @@ internal func _allASCII(_ input: UnsafeBufferPointer<UInt8>) -> Bool {
}
extension String {
@usableFromInline
internal static func _fromASCII(
internal static func _uncheckedFromASCII(
_ input: UnsafeBufferPointer<UInt8>
) -> String {
_internalInvariant(_allASCII(input), "not actually ASCII")
if let smol = _SmallString(input) {
return String(_StringGuts(smol))
}
@@ -63,6 +61,23 @@ extension String {
let storage = __StringStorage.create(initializingFrom: input, isASCII: true)
return storage.asString
}
@usableFromInline
internal static func _fromASCII(
_ input: UnsafeBufferPointer<UInt8>
) -> String {
_internalInvariant(_allASCII(input), "not actually ASCII")
return _uncheckedFromASCII(input)
}
internal static func _fromASCIIValidating(
_ input: UnsafeBufferPointer<UInt8>
) -> String? {
if _fastPath(_allASCII(input)) {
return _uncheckedFromASCII(input)
}
return nil
}
public // SPI(Foundation)
static func _tryFromUTF8(_ input: UnsafeBufferPointer<UInt8>) -> String? {
@@ -166,9 +181,9 @@ extension String {
return contents.withUnsafeBufferPointer { String._uncheckedFromUTF8($0) }
}
@usableFromInline @inline(never) // slow-path
internal static func _fromCodeUnits<
@inline(never) // slow path
private static func _slowFromCodeUnits<
Input: Collection,
Encoding: Unicode.Encoding
>(
@@ -194,6 +209,46 @@ extension String {
let str = contents.withUnsafeBufferPointer { String._uncheckedFromUTF8($0) }
return (str, repaired)
}
@usableFromInline @inline(never) // can't be inlined w/out breaking ABI
@_specialize(
where Input == UnsafeBufferPointer<UInt8>, Encoding == Unicode.ASCII)
@_specialize(
where Input == Array<UInt8>, Encoding == Unicode.ASCII)
internal static func _fromCodeUnits<
Input: Collection,
Encoding: Unicode.Encoding
>(
_ input: Input,
encoding: Encoding.Type,
repair: Bool
) -> (String, repairsMade: Bool)?
where Input.Element == Encoding.CodeUnit {
guard _fastPath(encoding == Unicode.ASCII.self) else {
return _slowFromCodeUnits(input, encoding: encoding, repair: repair)
}
var result:String? = nil
if let contigBytes = input as? _HasContiguousBytes,
contigBytes._providesContiguousBytesNoCopy {
result = contigBytes.withUnsafeBytes { rawBufPtr in
let buffer = UnsafeBufferPointer(
start: rawBufPtr.baseAddress?.assumingMemoryBound(to: UInt8.self),
count: rawBufPtr.count)
return String._fromASCIIValidating(buffer)
}
} else {
result = Array(input).withUnsafeBufferPointer {
let buffer = UnsafeRawBufferPointer($0).bindMemory(to: UInt8.self)
return String._fromASCIIValidating(buffer)
}
}
return result != nil ?
(result!, repairsMade: false) :
_slowFromCodeUnits(input, encoding: encoding, repair: repair)
}
public // @testable
static func _fromInvalidUTF16(