Skip to content

Commit 56081a2

Browse files
ktopley-applemoiseev
authored andcommitted
Add support for UnsafeRawBufferPointer to DispatchData (#8004)
* Add support for UnsafeRawBufferPointer to DispatchData (Radar 28503167) * Review comments.
1 parent dd1c661 commit 56081a2

File tree

2 files changed

+210
-1
lines changed

2 files changed

+210
-1
lines changed

stdlib/public/SDK/Dispatch/Data.swift

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,46 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
4444
///
4545
/// - parameter bytes: A pointer to the memory. It will be copied.
4646
/// - parameter count: The number of bytes to copy.
47+
@available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer) instead")
4748
public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
4849
__wrapped = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
4950
: _swift_dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
5051
_swift_dispatch_data_destructor_default()) as! __DispatchData
5152
}
5253

54+
/// Initialize a `Data` with copied memory content.
55+
///
56+
/// - parameter bytes: A pointer to the memory. It will be copied.
57+
/// - parameter count: The number of bytes to copy.
58+
public init(bytes buffer: UnsafeRawBufferPointer) {
59+
__wrapped = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
60+
: _swift_dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
61+
_swift_dispatch_data_destructor_default()) as! __DispatchData
62+
}
63+
5364
/// Initialize a `Data` without copying the bytes.
5465
///
5566
/// - parameter bytes: A pointer to the bytes.
5667
/// - parameter count: The size of the bytes.
5768
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
69+
@available(swift, deprecated: 4, message: "Use init(bytesNoCopy: UnsafeRawBufferPointer, deallocater: Deallocator) instead")
5870
public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
5971
let (q, b) = deallocator._deallocator
6072
__wrapped = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
6173
: _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, q, b) as! __DispatchData
6274
}
6375

76+
/// Initialize a `Data` without copying the bytes.
77+
///
78+
/// - parameter bytes: A pointer to the bytes.
79+
/// - parameter count: The size of the bytes.
80+
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
81+
public init(bytesNoCopy bytes: UnsafeRawBufferPointer, deallocator: Deallocator = .free) {
82+
let (q, b) = deallocator._deallocator
83+
__wrapped = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
84+
: _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, q, b) as! __DispatchData
85+
}
86+
6487
internal init(data: __DispatchData) {
6588
__wrapped = data
6689
}
@@ -97,11 +120,23 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
97120
///
98121
/// - parameter bytes: A pointer to the bytes to copy in to the data.
99122
/// - parameter count: The number of bytes to copy.
123+
@available(swift, deprecated: 4, message: "Use append(_: UnsafeRawBufferPointer) instead")
100124
public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
101125
let data = _swift_dispatch_data_create(bytes, count, nil, _swift_dispatch_data_destructor_default()) as! __DispatchData
102126
self.append(DispatchData(data: data))
103127
}
104128

129+
/// Append bytes to the data.
130+
///
131+
/// - parameter bytes: A pointer to the bytes to copy in to the data.
132+
/// - parameter count: The number of bytes to copy.
133+
public mutating func append(_ bytes: UnsafeRawBufferPointer) {
134+
// Nil base address does nothing.
135+
guard bytes.baseAddress != nil else { return }
136+
let data = _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, nil, _swift_dispatch_data_destructor_default()) as! __DispatchData
137+
self.append(DispatchData(data: data))
138+
}
139+
105140
/// Append data to the data.
106141
///
107142
/// - parameter data: The data to append to this data.
@@ -139,19 +174,43 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
139174
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
140175
/// - parameter count: The number of bytes to copy.
141176
/// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
177+
@available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, count: Int) instead")
142178
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
143179
_copyBytesHelper(to: pointer, from: 0..<count)
144180
}
145181

182+
/// Copy the contents of the data to a pointer.
183+
///
184+
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
185+
/// enough to hold `count` bytes.
186+
/// - parameter count: The number of bytes to copy.
187+
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, count: Int) {
188+
assert(count <= pointer.count, "Buffer too small to copy \(count) bytes")
189+
guard pointer.baseAddress != nil else { return }
190+
_copyBytesHelper(to: pointer.baseAddress!, from: 0..<count)
191+
}
192+
146193
/// Copy a subset of the contents of the data to a pointer.
147194
///
148195
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
149196
/// - parameter range: The range in the `Data` to copy.
150197
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
198+
@available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, from: CountableRange<Index>) instead")
151199
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
152200
_copyBytesHelper(to: pointer, from: range)
153201
}
154202

203+
/// Copy a subset of the contents of the data to a pointer.
204+
///
205+
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
206+
/// enough to hold `count` bytes.
207+
/// - parameter range: The range in the `Data` to copy.
208+
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange<Index>) {
209+
assert(range.count <= pointer.count, "Buffer too small to copy \(range.count) bytes")
210+
guard pointer.baseAddress != nil else { return }
211+
_copyBytesHelper(to: pointer.baseAddress!, from: range)
212+
}
213+
155214
/// Copy the contents of the data into a buffer.
156215
///
157216
/// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `MemoryLayout<DestinationType>.stride * buffer.count` then the first N bytes will be copied into the buffer.

test/stdlib/Dispatch.swift

Lines changed: 151 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ DispatchAPI.test("dispatch_data_t deallocator") {
7676
autoreleasepool {
7777
let size = 1024
7878
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
79-
let d = DispatchData(bytesNoCopy: UnsafeBufferPointer(start: p, count: size), deallocator: .custom(q, {
79+
let d = DispatchData(bytesNoCopy: UnsafeRawBufferPointer(start: p, count: size), deallocator: .custom(q, {
8080
t = 1
8181
}))
8282
}
@@ -278,6 +278,133 @@ DispatchAPI.test("DispatchData.copyBytes") {
278278
expectEqual(destPtr[5], 0xFF)
279279
}
280280

281+
DispatchAPI.test("DispatchData.copyBytesUnsafeRawBufferPointer") {
282+
let source1: [UInt8] = [0, 1, 2, 3]
283+
let srcPtr1 = UnsafeRawBufferPointer(start: source1, count: source1.count)
284+
285+
var dest: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
286+
let destPtr = UnsafeMutableRawBufferPointer(start: UnsafeMutablePointer(&dest),
287+
count: dest.count)
288+
var dispatchData = DispatchData(bytes: srcPtr1)
289+
290+
// Copy from offset 0
291+
dispatchData.copyBytes(to: destPtr, from: 0..<2)
292+
expectEqual(destPtr[0], 0)
293+
expectEqual(destPtr[1], 1)
294+
expectEqual(destPtr[2], 0xFF)
295+
expectEqual(destPtr[3], 0xFF)
296+
expectEqual(destPtr[4], 0xFF)
297+
expectEqual(destPtr[5], 0xFF)
298+
299+
// Copy from offset 2
300+
dispatchData.copyBytes(to: destPtr, from: 2..<4)
301+
expectEqual(destPtr[0], 2)
302+
expectEqual(destPtr[1], 3)
303+
expectEqual(destPtr[2], 0xFF)
304+
expectEqual(destPtr[3], 0xFF)
305+
expectEqual(destPtr[4], 0xFF)
306+
expectEqual(destPtr[5], 0xFF)
307+
308+
// Add two more regions
309+
let source2: [UInt8] = [0x10, 0x11, 0x12, 0x13]
310+
let srcPtr2 = UnsafeRawBufferPointer(start: source2, count: source2.count)
311+
dispatchData.append(DispatchData(bytes: srcPtr2))
312+
313+
let source3: [UInt8] = [0x14, 0x15, 0x16]
314+
let srcPtr3 = UnsafeRawBufferPointer(start: source3, count: source3.count)
315+
dispatchData.append(DispatchData(bytes: srcPtr3))
316+
317+
// Copy from offset 0. Copies across the first two regions
318+
dispatchData.copyBytes(to: destPtr, from: 0..<6)
319+
expectEqual(destPtr[0], 0)
320+
expectEqual(destPtr[1], 1)
321+
expectEqual(destPtr[2], 2)
322+
expectEqual(destPtr[3], 3)
323+
expectEqual(destPtr[4], 0x10)
324+
expectEqual(destPtr[5], 0x11)
325+
326+
// Copy from offset 2. Copies across the first two regions
327+
dispatchData.copyBytes(to: destPtr, from: 2..<8)
328+
expectEqual(destPtr[0], 2)
329+
expectEqual(destPtr[1], 3)
330+
expectEqual(destPtr[2], 0x10)
331+
expectEqual(destPtr[3], 0x11)
332+
expectEqual(destPtr[4], 0x12)
333+
expectEqual(destPtr[5], 0x13)
334+
335+
// Copy from offset 3. Copies across all three regions
336+
dispatchData.copyBytes(to: destPtr, from: 3..<9)
337+
expectEqual(destPtr[0], 3)
338+
expectEqual(destPtr[1], 0x10)
339+
expectEqual(destPtr[2], 0x11)
340+
expectEqual(destPtr[3], 0x12)
341+
expectEqual(destPtr[4], 0x13)
342+
expectEqual(destPtr[5], 0x14)
343+
344+
// Copy from offset 5. Skips the first region and the first byte of the second
345+
dispatchData.copyBytes(to: destPtr, from: 5..<11)
346+
expectEqual(destPtr[0], 0x11)
347+
expectEqual(destPtr[1], 0x12)
348+
expectEqual(destPtr[2], 0x13)
349+
expectEqual(destPtr[3], 0x14)
350+
expectEqual(destPtr[4], 0x15)
351+
expectEqual(destPtr[5], 0x16)
352+
353+
// Copy from offset 8. Skips the first two regions
354+
destPtr[3] = 0xFF
355+
destPtr[4] = 0xFF
356+
destPtr[5] = 0xFF
357+
dispatchData.copyBytes(to: destPtr, from: 8..<11)
358+
expectEqual(destPtr[0], 0x14)
359+
expectEqual(destPtr[1], 0x15)
360+
expectEqual(destPtr[2], 0x16)
361+
expectEqual(destPtr[3], 0xFF)
362+
expectEqual(destPtr[4], 0xFF)
363+
expectEqual(destPtr[5], 0xFF)
364+
365+
// Copy from offset 9. Skips the first two regions and the first byte of the third
366+
destPtr[2] = 0xFF
367+
destPtr[3] = 0xFF
368+
destPtr[4] = 0xFF
369+
destPtr[5] = 0xFF
370+
dispatchData.copyBytes(to: destPtr, from: 9..<11)
371+
expectEqual(destPtr[0], 0x15)
372+
expectEqual(destPtr[1], 0x16)
373+
expectEqual(destPtr[2], 0xFF)
374+
expectEqual(destPtr[3], 0xFF)
375+
expectEqual(destPtr[4], 0xFF)
376+
expectEqual(destPtr[5], 0xFF)
377+
378+
// Copy from offset 9, but only 1 byte. Ends before the end of the data
379+
destPtr[1] = 0xFF
380+
destPtr[2] = 0xFF
381+
destPtr[3] = 0xFF
382+
destPtr[4] = 0xFF
383+
destPtr[5] = 0xFF
384+
dispatchData.copyBytes(to: destPtr, from: 9..<10)
385+
expectEqual(destPtr[0], 0x15)
386+
expectEqual(destPtr[1], 0xFF)
387+
expectEqual(destPtr[2], 0xFF)
388+
expectEqual(destPtr[3], 0xFF)
389+
expectEqual(destPtr[4], 0xFF)
390+
expectEqual(destPtr[5], 0xFF)
391+
392+
// Copy from offset 2, but only 1 byte. This copy is bounded within the
393+
// first region.
394+
destPtr[1] = 0xFF
395+
destPtr[2] = 0xFF
396+
destPtr[3] = 0xFF
397+
destPtr[4] = 0xFF
398+
destPtr[5] = 0xFF
399+
dispatchData.copyBytes(to: destPtr, from: 2..<3)
400+
expectEqual(destPtr[0], 2)
401+
expectEqual(destPtr[1], 0xFF)
402+
expectEqual(destPtr[2], 0xFF)
403+
expectEqual(destPtr[3], 0xFF)
404+
expectEqual(destPtr[4], 0xFF)
405+
expectEqual(destPtr[5], 0xFF)
406+
}
407+
281408
DispatchAPI.test("DispatchData.buffers") {
282409
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
283410
var ptr = UnsafeBufferPointer<UInt8>(start: bytes, count: bytes.count)
@@ -301,3 +428,26 @@ DispatchAPI.test("DispatchData.buffers") {
301428
expectEqual(data.count, 0)
302429
}
303430

431+
DispatchAPI.test("DispatchData.bufferUnsafeRawBufferPointer") {
432+
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
433+
var ptr = UnsafeRawBufferPointer(start: bytes, count: bytes.count)
434+
var data = DispatchData(bytes: ptr)
435+
expectEqual(bytes.count, data.count)
436+
for i in 0..<data.count {
437+
expectEqual(data[i], bytes[i])
438+
}
439+
440+
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
441+
expectEqual(bytes.count, data.count)
442+
for i in 0..<data.count {
443+
expectEqual(data[i], bytes[i])
444+
}
445+
446+
ptr = UnsafeRawBufferPointer(start: nil, count: 0)
447+
data = DispatchData(bytes: ptr)
448+
expectEqual(data.count, 0)
449+
450+
data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
451+
expectEqual(data.count, 0)
452+
}
453+

0 commit comments

Comments
 (0)