Skip to content

Commit d6bf8e3

Browse files
authored
[Foundation] adjust inline of append and initialization functions (#17027)
* [Foundation] adjust inline of append and initialization functions and use _copyContents(initialzing:) to avoid performance regressions while using generic collection/sequence APIs * Add the Array<UInt8> specialization back for append to Data
1 parent 9617cef commit d6bf8e3

File tree

1 file changed

+27
-57
lines changed

1 file changed

+27
-57
lines changed

stdlib/public/SDK/Foundation/Data.swift

Lines changed: 27 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,28 +1122,6 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
11221122
_sliceRange = 0..<count
11231123
}
11241124

1125-
/// Initialize a `Data` with the contents of an Array.
1126-
///
1127-
/// - parameter bytes: An array of bytes to copy.
1128-
public init(bytes: Array<UInt8>) {
1129-
let count = bytes.count
1130-
_backing = bytes.withUnsafeBufferPointer {
1131-
return _DataStorage(bytes: $0.baseAddress, length: count)
1132-
}
1133-
_sliceRange = 0..<count
1134-
}
1135-
1136-
/// Initialize a `Data` with the contents of an Array.
1137-
///
1138-
/// - parameter bytes: An array of bytes to copy.
1139-
public init(bytes: ArraySlice<UInt8>) {
1140-
let count = bytes.count
1141-
_backing = bytes.withUnsafeBufferPointer {
1142-
return _DataStorage(bytes: $0.baseAddress, length: count)
1143-
}
1144-
_sliceRange = 0..<count
1145-
}
1146-
11471125
/// Initialize a `Data` with a repeating byte pattern
11481126
///
11491127
/// - parameter repeatedValue: A byte to initialize the pattern
@@ -1260,30 +1238,20 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
12601238
}
12611239

12621240
// slightly faster paths for common sequences
1263-
1241+
@inlinable
12641242
public init<S: Sequence>(_ elements: S) where S.Iterator.Element == UInt8 {
1265-
if elements is Array<UInt8> {
1266-
self.init(bytes: _identityCast(elements, to: Array<UInt8>.self))
1267-
} else if elements is ArraySlice<UInt8> {
1268-
self.init(bytes: _identityCast(elements, to: ArraySlice<UInt8>.self))
1269-
} else if elements is UnsafeBufferPointer<UInt8> {
1270-
self.init(buffer: _identityCast(elements, to: UnsafeBufferPointer<UInt8>.self))
1271-
} else if let buffer = elements as? UnsafeMutableBufferPointer<UInt8> {
1272-
self.init(buffer: buffer)
1273-
} else if let data = elements as? Data {
1274-
let len = data.count
1275-
let backing = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
1276-
return _DataStorage(bytes: bytes, length: len)
1277-
}
1278-
self.init(backing: backing, range: 0..<len)
1279-
} else {
1280-
let underestimatedCount = elements.underestimatedCount
1281-
self.init(count: underestimatedCount)
1282-
1283-
let (endIterator, _) = UnsafeMutableBufferPointer(start: _backing._bytes?.assumingMemoryBound(to: UInt8.self), count: underestimatedCount).initialize(from: elements)
1284-
var iter = endIterator
1285-
while let byte = iter.next() { self.append(byte) }
1243+
let backing = _DataStorage(capacity: Swift.max(elements.underestimatedCount, 1))
1244+
var (iter, endIndex) = elements._copyContents(initializing: UnsafeMutableBufferPointer(start: backing._bytes?.bindMemory(to: UInt8.self, capacity: backing._capacity), count: backing._capacity))
1245+
backing._length = endIndex
1246+
while var element = iter.next() {
1247+
backing.append(&element, length: 1)
12861248
}
1249+
self.init(backing: backing, range: 0..<backing._length)
1250+
}
1251+
1252+
@inlinable
1253+
public init<S: Sequence>(bytes elements: S) where S.Iterator.Element == UInt8 {
1254+
self.init(elements)
12871255
}
12881256

12891257
@usableFromInline
@@ -1506,17 +1474,25 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
15061474
_append(buffer)
15071475
}
15081476

1509-
public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element {
1510-
for byte in newElements {
1511-
append(byte)
1512-
}
1513-
}
1514-
15151477
public mutating func append(contentsOf bytes: [UInt8]) {
15161478
bytes.withUnsafeBufferPointer { (buffer: UnsafeBufferPointer<UInt8>) -> Void in
15171479
_append(buffer)
15181480
}
15191481
}
1482+
1483+
@inlinable
1484+
public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element {
1485+
let underestimatedCount = Swift.max(newElements.underestimatedCount, 1)
1486+
_withStackOrHeapBuffer(underestimatedCount) { (buffer) in
1487+
let capacity = buffer.pointee.capacity
1488+
let base = buffer.pointee.memory.bindMemory(to: UInt8.self, capacity: capacity)
1489+
var (iter, endIndex) = newElements._copyContents(initializing: UnsafeMutableBufferPointer(start: base, count: capacity))
1490+
_append(UnsafeBufferPointer(start: base, count: endIndex))
1491+
while var element = iter.next() {
1492+
append(&element, count: 1)
1493+
}
1494+
}
1495+
}
15201496

15211497
// MARK: -
15221498

@@ -1897,13 +1873,7 @@ extension Data {
18971873

18981874
/// Provides bridging functionality for struct Data to class NSData and vice-versa.
18991875

1900-
#if DEPLOYMENT_RUNTIME_SWIFT
1901-
internal typealias DataBridgeType = _ObjectTypeBridgeable
1902-
#else
1903-
internal typealias DataBridgeType = _ObjectiveCBridgeable
1904-
#endif
1905-
1906-
extension Data : DataBridgeType {
1876+
extension Data : _ObjectiveCBridgeable {
19071877
@_semantics("convertToObjectiveC")
19081878
public func _bridgeToObjectiveC() -> NSData {
19091879
return _backing.bridgedReference(_sliceRange)

0 commit comments

Comments
 (0)