@@ -62,6 +62,39 @@ internal func __NSDataIsCompact(_ data: NSData) -> Bool {
62
62
63
63
#endif
64
64
65
+ @_alwaysEmitIntoClient
66
+ internal func _withStackOrHeapBuffer( capacity: Int , _ body: ( UnsafeMutableBufferPointer < UInt8 > ) -> Void ) {
67
+ guard capacity > 0 else {
68
+ body ( UnsafeMutableBufferPointer ( start: nil , count: 0 ) )
69
+ return
70
+ }
71
+ typealias InlineBuffer = ( // 32 bytes
72
+ UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 ,
73
+ UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 ,
74
+ UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 ,
75
+ UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8 , UInt8
76
+ )
77
+ let inlineCount = MemoryLayout< InlineBuffer> . size
78
+ if capacity <= inlineCount {
79
+ var buffer : InlineBuffer = (
80
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
81
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
82
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ,
83
+ 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
84
+ )
85
+ withUnsafeMutableBytes ( of: & buffer) { buffer in
86
+ assert ( buffer. count == inlineCount)
87
+ let start = buffer. baseAddress!. assumingMemoryBound ( to: UInt8 . self)
88
+ body ( UnsafeMutableBufferPointer ( start: start, count: capacity) )
89
+ }
90
+ return
91
+ }
92
+
93
+ let buffer = UnsafeMutableBufferPointer< UInt8> . allocate( capacity: capacity)
94
+ defer { buffer. deallocate ( ) }
95
+ body ( buffer)
96
+ }
97
+
65
98
// Underlying storage representation for medium and large data.
66
99
// Inlinability strategy: methods from here should not inline into InlineSlice or LargeSlice unless trivial.
67
100
// NOTE: older overlays called this class _DataStorage. The two must
@@ -2054,44 +2087,43 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
2054
2087
// The sequence might still be able to provide direct access to typed memory.
2055
2088
// NOTE: It's safe to do this because we're already guarding on S's element as `UInt8`. This would not be safe on arbitrary sequences.
2056
2089
let representation = elements. withContiguousStorageIfAvailable {
2057
- return _Representation ( UnsafeRawBufferPointer ( $0) )
2090
+ _Representation ( UnsafeRawBufferPointer ( $0) )
2058
2091
}
2059
-
2060
2092
if let representation = representation {
2061
2093
_representation = representation
2062
- } else {
2063
- // Dummy assignment so we can capture below.
2064
- _representation = _Representation ( capacity: 0 )
2065
-
2066
- // Copy as much as we can in one shot from the sequence.
2067
- let underestimatedCount = Swift . max ( elements. underestimatedCount, 1 )
2068
- _withStackOrHeapBuffer ( underestimatedCount) { ( buffer) in
2069
- // In order to copy from the sequence, we have to bind the buffer to UInt8.
2070
- // This is safe since we'll copy out of this buffer as raw memory later.
2071
- let capacity = buffer. pointee. capacity
2072
- let base = buffer. pointee. memory. bindMemory ( to: UInt8 . self, capacity: capacity)
2073
- var ( iter, endIndex) = elements. _copyContents ( initializing: UnsafeMutableBufferPointer ( start: base, count: capacity) )
2074
-
2075
- // Copy the contents of buffer...
2076
- _representation = _Representation ( UnsafeRawBufferPointer ( start: base, count: endIndex) )
2077
-
2078
- // ... and append the rest byte-wise, buffering through an InlineData.
2079
- var buffer = InlineData ( )
2080
- while let element = iter. next ( ) {
2081
- buffer. append ( byte: element)
2082
- if buffer. count == buffer. capacity {
2083
- buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2084
- buffer. count = 0
2085
- }
2086
- }
2094
+ return
2095
+ }
2087
2096
2088
- // If we've still got bytes left in the buffer (i.e. the loop ended before we filled up the buffer and cleared it out), append them.
2089
- if buffer. count > 0 {
2090
- buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2091
- buffer. count = 0
2092
- }
2097
+ // Copy as much as we can in one shot from the sequence.
2098
+ let underestimatedCount = elements. underestimatedCount
2099
+ _representation = _Representation ( count: underestimatedCount)
2100
+ var ( iter, endIndex) : ( S . Iterator , Int ) = _representation. withUnsafeMutableBytes { buffer in
2101
+ let start = buffer. baseAddress!. assumingMemoryBound ( to: UInt8 . self)
2102
+ let b = UnsafeMutableBufferPointer ( start: start, count: buffer. count)
2103
+ return elements. _copyContents ( initializing: b)
2104
+ }
2105
+ guard endIndex == _representation. count else {
2106
+ // We can't trap here. We have to allow an underfilled buffer
2107
+ // to emulate the previous implementation.
2108
+ _representation. replaceSubrange ( endIndex ..< _representation. endIndex, with: nil , count: 0 )
2109
+ return
2110
+ }
2111
+
2112
+ // Append the rest byte-wise, buffering through an InlineData.
2113
+ var buffer = InlineData ( )
2114
+ while let element = iter. next ( ) {
2115
+ buffer. append ( byte: element)
2116
+ if buffer. count == buffer. capacity {
2117
+ buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2118
+ buffer. count = 0
2093
2119
}
2094
2120
}
2121
+
2122
+ // If we've still got bytes left in the buffer (i.e. the loop ended before we filled up the buffer and cleared it out), append them.
2123
+ if buffer. count > 0 {
2124
+ buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2125
+ buffer. count = 0
2126
+ }
2095
2127
}
2096
2128
2097
2129
@available ( swift, introduced: 4.2 )
@@ -2347,43 +2379,43 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
2347
2379
2348
2380
// The sequence might still be able to provide direct access to typed memory.
2349
2381
// NOTE: It's safe to do this because we're already guarding on S's element as `UInt8`. This would not be safe on arbitrary sequences.
2350
- var appended = false
2351
- elements. withContiguousStorageIfAvailable {
2382
+ let appended : Void ? = elements. withContiguousStorageIfAvailable {
2352
2383
_representation. append ( contentsOf: UnsafeRawBufferPointer ( $0) )
2353
- appended = true
2354
2384
}
2355
-
2356
- guard !appended else { return }
2385
+ guard appended == nil else { return }
2357
2386
2358
2387
// The sequence is really not contiguous.
2359
2388
// Copy as much as we can in one shot.
2360
- let underestimatedCount = Swift . max ( elements. underestimatedCount, 1 )
2361
- _withStackOrHeapBuffer ( underestimatedCount) { ( buffer) in
2362
- // In order to copy from the sequence, we have to bind the temporary buffer to `UInt8`.
2363
- // This is safe since we're the only owners of the buffer and we copy out as raw memory below anyway.
2364
- let capacity = buffer. pointee. capacity
2365
- let base = buffer. pointee. memory. bindMemory ( to: UInt8 . self, capacity: capacity)
2366
- var ( iter, endIndex) = elements. _copyContents ( initializing: UnsafeMutableBufferPointer ( start: base, count: capacity) )
2367
-
2368
- // Copy the contents of the buffer...
2369
- _representation. append ( contentsOf: UnsafeRawBufferPointer ( start: base, count: endIndex) )
2370
-
2371
- // ... and append the rest byte-wise, buffering through an InlineData.
2372
- var buffer = InlineData ( )
2373
- while let element = iter. next ( ) {
2374
- buffer. append ( byte: element)
2375
- if buffer. count == buffer. capacity {
2376
- buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2377
- buffer. count = 0
2378
- }
2379
- }
2389
+ let underestimatedCount = elements. underestimatedCount
2390
+ let originalCount = _representation. count
2391
+ _representation. count += underestimatedCount
2392
+ var ( iter, endIndex) : ( S . Iterator , Int ) = _representation. withUnsafeMutableBytes { buffer in
2393
+ let start = buffer. baseAddress!. assumingMemoryBound ( to: UInt8 . self) + originalCount
2394
+ let b = UnsafeMutableBufferPointer ( start: start, count: buffer. count - originalCount)
2395
+ return elements. _copyContents ( initializing: b)
2396
+ }
2397
+ guard endIndex == underestimatedCount else {
2398
+ // We can't trap here. We have to allow an underfilled buffer
2399
+ // to emulate the previous implementation.
2400
+ _representation. replaceSubrange ( originalCount + endIndex ..< _representation. endIndex, with: nil , count: 0 )
2401
+ return
2402
+ }
2380
2403
2381
- // If we've still got bytes left in the buffer (i.e. the loop ended before we filled up the buffer and cleared it out), append them.
2382
- if buffer. count > 0 {
2404
+ // Append the rest byte-wise, buffering through an InlineData.
2405
+ var buffer = InlineData ( )
2406
+ while let element = iter. next ( ) {
2407
+ buffer. append ( byte: element)
2408
+ if buffer. count == buffer. capacity {
2383
2409
buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2384
2410
buffer. count = 0
2385
2411
}
2386
2412
}
2413
+
2414
+ // If we've still got bytes left in the buffer (i.e. the loop ended before we filled up the buffer and cleared it out), append them.
2415
+ if buffer. count > 0 {
2416
+ buffer. withUnsafeBytes { _representation. append ( contentsOf: $0) }
2417
+ buffer. count = 0
2418
+ }
2387
2419
}
2388
2420
2389
2421
// MARK: -
@@ -2436,15 +2468,26 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
2436
2468
/// - parameter newElements: The replacement bytes.
2437
2469
@inlinable // This is @inlinable as generic and reasonably small.
2438
2470
public mutating func replaceSubrange< ByteCollection : Collection > ( _ subrange: Range < Index > , with newElements: ByteCollection ) where ByteCollection. Iterator. Element == Data . Iterator . Element {
2471
+ // If the collection is already contiguous, access the underlying raw memory directly.
2472
+ if let contiguous = newElements as? ContiguousBytes {
2473
+ contiguous. withUnsafeBytes { buffer in
2474
+ _representation. replaceSubrange ( subrange, with: buffer. baseAddress, count: buffer. count)
2475
+ }
2476
+ return
2477
+ }
2478
+ // The collection might still be able to provide direct access to typed memory.
2479
+ // NOTE: It's safe to do this because we're already guarding on ByteCollection's element as `UInt8`. This would not be safe on arbitrary collections.
2480
+ let replaced : Void ? = newElements. withContiguousStorageIfAvailable { buffer in
2481
+ _representation. replaceSubrange ( subrange, with: buffer. baseAddress, count: buffer. count)
2482
+ }
2483
+ guard replaced == nil else { return }
2484
+
2439
2485
let totalCount = Int ( newElements. count)
2440
- _withStackOrHeapBuffer ( totalCount) { conditionalBuffer in
2441
- let buffer = UnsafeMutableBufferPointer ( start: conditionalBuffer. pointee. memory. assumingMemoryBound ( to: UInt8 . self) , count: totalCount)
2486
+ _withStackOrHeapBuffer ( capacity: totalCount) { buffer in
2442
2487
var ( iterator, index) = newElements. _copyContents ( initializing: buffer)
2443
- while let byte = iterator. next ( ) {
2444
- buffer [ index] = byte
2445
- index = buffer. index ( after: index)
2446
- }
2447
- replaceSubrange ( subrange, with: conditionalBuffer. pointee. memory, count: totalCount)
2488
+ precondition ( index == buffer. endIndex, " Collection has less elements than its count " )
2489
+ precondition ( iterator. next ( ) == nil , " Collection has more elements than its count " )
2490
+ _representation. replaceSubrange ( subrange, with: buffer. baseAddress, count: totalCount)
2448
2491
}
2449
2492
}
2450
2493
0 commit comments