Skip to content

Commit 8730836

Browse files
committed
Add support for UnsafeRawBufferPointer to DispatchData
(Radar 28503167)
1 parent e02de50 commit 8730836

File tree

2 files changed

+209
-1
lines changed

2 files changed

+209
-1
lines changed

stdlib/public/SDK/Dispatch/Data.swift

Lines changed: 57 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(bytes: 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,41 @@ 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.
185+
/// - parameter count: The number of bytes to copy.
186+
/// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
187+
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, count: Int) {
188+
guard pointer.baseAddress != nil else { return }
189+
_copyBytesHelper(to: pointer.baseAddress!, from: 0..<count)
190+
}
191+
146192
/// Copy a subset of the contents of the data to a pointer.
147193
///
148194
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
149195
/// - parameter range: The range in the `Data` to copy.
150196
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
197+
@available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, from: CountableRange<Index>) instead")
151198
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
152199
_copyBytesHelper(to: pointer, from: range)
153200
}
154201

202+
/// Copy a subset of the contents of the data to a pointer.
203+
///
204+
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
205+
/// - parameter range: The range in the `Data` to copy.
206+
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
207+
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange<Index>) {
208+
guard pointer.baseAddress != nil else { return }
209+
_copyBytesHelper(to: pointer.baseAddress!, from: range)
210+
}
211+
155212
/// Copy the contents of the data into a buffer.
156213
///
157214
/// 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: 152 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,134 @@ 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+
289+
var dispatchData = DispatchData(bytes: srcPtr1)
290+
291+
// Copy from offset 0
292+
dispatchData.copyBytes(to: destPtr, from: 0..<2)
293+
expectEqual(destPtr[0], 0)
294+
expectEqual(destPtr[1], 1)
295+
expectEqual(destPtr[2], 0xFF)
296+
expectEqual(destPtr[3], 0xFF)
297+
expectEqual(destPtr[4], 0xFF)
298+
expectEqual(destPtr[5], 0xFF)
299+
300+
// Copy from offset 2
301+
dispatchData.copyBytes(to: destPtr, from: 2..<4)
302+
expectEqual(destPtr[0], 2)
303+
expectEqual(destPtr[1], 3)
304+
expectEqual(destPtr[2], 0xFF)
305+
expectEqual(destPtr[3], 0xFF)
306+
expectEqual(destPtr[4], 0xFF)
307+
expectEqual(destPtr[5], 0xFF)
308+
309+
// Add two more regions
310+
let source2: [UInt8] = [0x10, 0x11, 0x12, 0x13]
311+
let srcPtr2 = UnsafeRawBufferPointer(start: source2, count: source2.count)
312+
dispatchData.append(DispatchData(bytes: srcPtr2))
313+
314+
let source3: [UInt8] = [0x14, 0x15, 0x16]
315+
let srcPtr3 = UnsafeRawBufferPointer(start: source3, count: source3.count)
316+
dispatchData.append(DispatchData(bytes: srcPtr3))
317+
318+
// Copy from offset 0. Copies across the first two regions
319+
dispatchData.copyBytes(to: destPtr, from: 0..<6)
320+
expectEqual(destPtr[0], 0)
321+
expectEqual(destPtr[1], 1)
322+
expectEqual(destPtr[2], 2)
323+
expectEqual(destPtr[3], 3)
324+
expectEqual(destPtr[4], 0x10)
325+
expectEqual(destPtr[5], 0x11)
326+
327+
// Copy from offset 2. Copies across the first two regions
328+
dispatchData.copyBytes(to: destPtr, from: 2..<8)
329+
expectEqual(destPtr[0], 2)
330+
expectEqual(destPtr[1], 3)
331+
expectEqual(destPtr[2], 0x10)
332+
expectEqual(destPtr[3], 0x11)
333+
expectEqual(destPtr[4], 0x12)
334+
expectEqual(destPtr[5], 0x13)
335+
336+
// Copy from offset 3. Copies across all three regions
337+
dispatchData.copyBytes(to: destPtr, from: 3..<9)
338+
expectEqual(destPtr[0], 3)
339+
expectEqual(destPtr[1], 0x10)
340+
expectEqual(destPtr[2], 0x11)
341+
expectEqual(destPtr[3], 0x12)
342+
expectEqual(destPtr[4], 0x13)
343+
expectEqual(destPtr[5], 0x14)
344+
345+
// Copy from offset 5. Skips the first region and the first byte of the second
346+
dispatchData.copyBytes(to: destPtr, from: 5..<11)
347+
expectEqual(destPtr[0], 0x11)
348+
expectEqual(destPtr[1], 0x12)
349+
expectEqual(destPtr[2], 0x13)
350+
expectEqual(destPtr[3], 0x14)
351+
expectEqual(destPtr[4], 0x15)
352+
expectEqual(destPtr[5], 0x16)
353+
354+
// Copy from offset 8. Skips the first two regions
355+
destPtr[3] = 0xFF
356+
destPtr[4] = 0xFF
357+
destPtr[5] = 0xFF
358+
dispatchData.copyBytes(to: destPtr, from: 8..<11)
359+
expectEqual(destPtr[0], 0x14)
360+
expectEqual(destPtr[1], 0x15)
361+
expectEqual(destPtr[2], 0x16)
362+
expectEqual(destPtr[3], 0xFF)
363+
expectEqual(destPtr[4], 0xFF)
364+
expectEqual(destPtr[5], 0xFF)
365+
366+
// Copy from offset 9. Skips the first two regions and the first byte of the third
367+
destPtr[2] = 0xFF
368+
destPtr[3] = 0xFF
369+
destPtr[4] = 0xFF
370+
destPtr[5] = 0xFF
371+
dispatchData.copyBytes(to: destPtr, from: 9..<11)
372+
expectEqual(destPtr[0], 0x15)
373+
expectEqual(destPtr[1], 0x16)
374+
expectEqual(destPtr[2], 0xFF)
375+
expectEqual(destPtr[3], 0xFF)
376+
expectEqual(destPtr[4], 0xFF)
377+
expectEqual(destPtr[5], 0xFF)
378+
379+
// Copy from offset 9, but only 1 byte. Ends before the end of the data
380+
destPtr[1] = 0xFF
381+
destPtr[2] = 0xFF
382+
destPtr[3] = 0xFF
383+
destPtr[4] = 0xFF
384+
destPtr[5] = 0xFF
385+
dispatchData.copyBytes(to: destPtr, from: 9..<10)
386+
expectEqual(destPtr[0], 0x15)
387+
expectEqual(destPtr[1], 0xFF)
388+
expectEqual(destPtr[2], 0xFF)
389+
expectEqual(destPtr[3], 0xFF)
390+
expectEqual(destPtr[4], 0xFF)
391+
expectEqual(destPtr[5], 0xFF)
392+
393+
// Copy from offset 2, but only 1 byte. This copy is bounded within the
394+
// first region.
395+
destPtr[1] = 0xFF
396+
destPtr[2] = 0xFF
397+
destPtr[3] = 0xFF
398+
destPtr[4] = 0xFF
399+
destPtr[5] = 0xFF
400+
dispatchData.copyBytes(to: destPtr, from: 2..<3)
401+
expectEqual(destPtr[0], 2)
402+
expectEqual(destPtr[1], 0xFF)
403+
expectEqual(destPtr[2], 0xFF)
404+
expectEqual(destPtr[3], 0xFF)
405+
expectEqual(destPtr[4], 0xFF)
406+
expectEqual(destPtr[5], 0xFF)
407+
}
408+
281409
DispatchAPI.test("DispatchData.buffers") {
282410
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
283411
var ptr = UnsafeBufferPointer<UInt8>(start: bytes, count: bytes.count)
@@ -301,3 +429,26 @@ DispatchAPI.test("DispatchData.buffers") {
301429
expectEqual(data.count, 0)
302430
}
303431

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

0 commit comments

Comments
 (0)