Skip to content

Add support for UnsafeRawBufferPointer to DispatchData #8004

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 10, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions stdlib/public/SDK/Dispatch/Data.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,23 +44,46 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
///
/// - parameter bytes: A pointer to the memory. It will be copied.
/// - parameter count: The number of bytes to copy.
@available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer) instead")
public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
__wrapped = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
: _swift_dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
_swift_dispatch_data_destructor_default()) as! __DispatchData
}

/// Initialize a `Data` with copied memory content.
///
/// - parameter bytes: A pointer to the memory. It will be copied.
/// - parameter count: The number of bytes to copy.
public init(bytes buffer: UnsafeRawBufferPointer) {
__wrapped = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
: _swift_dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
_swift_dispatch_data_destructor_default()) as! __DispatchData
}

/// Initialize a `Data` without copying the bytes.
///
/// - parameter bytes: A pointer to the bytes.
/// - parameter count: The size of the bytes.
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
@available(swift, deprecated: 4, message: "Use init(bytesNoCopy: UnsafeRawBufferPointer, deallocater: Deallocator) instead")
public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
let (q, b) = deallocator._deallocator
__wrapped = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
: _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, q, b) as! __DispatchData
}

/// Initialize a `Data` without copying the bytes.
///
/// - parameter bytes: A pointer to the bytes.
/// - parameter count: The size of the bytes.
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
public init(bytesNoCopy bytes: UnsafeRawBufferPointer, deallocator: Deallocator = .free) {
let (q, b) = deallocator._deallocator
__wrapped = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
: _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, q, b) as! __DispatchData
}

internal init(data: __DispatchData) {
__wrapped = data
}
Expand Down Expand Up @@ -97,11 +120,23 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
///
/// - parameter bytes: A pointer to the bytes to copy in to the data.
/// - parameter count: The number of bytes to copy.
@available(swift, deprecated: 4, message: "Use append(_: UnsafeRawBufferPointer) instead")
public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
let data = _swift_dispatch_data_create(bytes, count, nil, _swift_dispatch_data_destructor_default()) as! __DispatchData
self.append(DispatchData(data: data))
}

/// Append bytes to the data.
///
/// - parameter bytes: A pointer to the bytes to copy in to the data.
/// - parameter count: The number of bytes to copy.
public mutating func append(_ bytes: UnsafeRawBufferPointer) {
// Nil base address does nothing.
guard bytes.baseAddress != nil else { return }
let data = _swift_dispatch_data_create(bytes.baseAddress!, bytes.count, nil, _swift_dispatch_data_destructor_default()) as! __DispatchData
self.append(DispatchData(data: data))
}

/// Append data to the data.
///
/// - parameter data: The data to append to this data.
Expand Down Expand Up @@ -139,19 +174,43 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable {
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
/// - parameter count: The number of bytes to copy.
/// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
@available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, count: Int) instead")
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
_copyBytesHelper(to: pointer, from: 0..<count)
}

/// Copy the contents of the data to a pointer.
///
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
/// enough to hold `count` bytes.
/// - parameter count: The number of bytes to copy.
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, count: Int) {
assert(count <= pointer.count, "Buffer too small to copy \(count) bytes")
guard pointer.baseAddress != nil else { return }
_copyBytesHelper(to: pointer.baseAddress!, from: 0..<count)
}

/// Copy a subset of the contents of the data to a pointer.
///
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
/// - parameter range: The range in the `Data` to copy.
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
@available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, from: CountableRange<Index>) instead")
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
_copyBytesHelper(to: pointer, from: range)
}

/// Copy a subset of the contents of the data to a pointer.
///
/// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
/// enough to hold `count` bytes.
/// - parameter range: The range in the `Data` to copy.
public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange<Index>) {
assert(range.count <= pointer.count, "Buffer too small to copy \(range.count) bytes")
guard pointer.baseAddress != nil else { return }
_copyBytesHelper(to: pointer.baseAddress!, from: range)
}

/// Copy the contents of the data into a buffer.
///
/// 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.
Expand Down
152 changes: 151 additions & 1 deletion test/stdlib/Dispatch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ DispatchAPI.test("dispatch_data_t deallocator") {
autoreleasepool {
let size = 1024
let p = UnsafeMutablePointer<UInt8>.allocate(capacity: size)
let d = DispatchData(bytesNoCopy: UnsafeBufferPointer(start: p, count: size), deallocator: .custom(q, {
let d = DispatchData(bytesNoCopy: UnsafeRawBufferPointer(start: p, count: size), deallocator: .custom(q, {
t = 1
}))
}
Expand Down Expand Up @@ -278,6 +278,133 @@ DispatchAPI.test("DispatchData.copyBytes") {
expectEqual(destPtr[5], 0xFF)
}

DispatchAPI.test("DispatchData.copyBytesUnsafeRawBufferPointer") {
let source1: [UInt8] = [0, 1, 2, 3]
let srcPtr1 = UnsafeRawBufferPointer(start: source1, count: source1.count)

var dest: [UInt8] = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
let destPtr = UnsafeMutableRawBufferPointer(start: UnsafeMutablePointer(&dest),
count: dest.count)
var dispatchData = DispatchData(bytes: srcPtr1)

// Copy from offset 0
dispatchData.copyBytes(to: destPtr, from: 0..<2)
expectEqual(destPtr[0], 0)
expectEqual(destPtr[1], 1)
expectEqual(destPtr[2], 0xFF)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)

// Copy from offset 2
dispatchData.copyBytes(to: destPtr, from: 2..<4)
expectEqual(destPtr[0], 2)
expectEqual(destPtr[1], 3)
expectEqual(destPtr[2], 0xFF)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)

// Add two more regions
let source2: [UInt8] = [0x10, 0x11, 0x12, 0x13]
let srcPtr2 = UnsafeRawBufferPointer(start: source2, count: source2.count)
dispatchData.append(DispatchData(bytes: srcPtr2))

let source3: [UInt8] = [0x14, 0x15, 0x16]
let srcPtr3 = UnsafeRawBufferPointer(start: source3, count: source3.count)
dispatchData.append(DispatchData(bytes: srcPtr3))

// Copy from offset 0. Copies across the first two regions
dispatchData.copyBytes(to: destPtr, from: 0..<6)
expectEqual(destPtr[0], 0)
expectEqual(destPtr[1], 1)
expectEqual(destPtr[2], 2)
expectEqual(destPtr[3], 3)
expectEqual(destPtr[4], 0x10)
expectEqual(destPtr[5], 0x11)

// Copy from offset 2. Copies across the first two regions
dispatchData.copyBytes(to: destPtr, from: 2..<8)
expectEqual(destPtr[0], 2)
expectEqual(destPtr[1], 3)
expectEqual(destPtr[2], 0x10)
expectEqual(destPtr[3], 0x11)
expectEqual(destPtr[4], 0x12)
expectEqual(destPtr[5], 0x13)

// Copy from offset 3. Copies across all three regions
dispatchData.copyBytes(to: destPtr, from: 3..<9)
expectEqual(destPtr[0], 3)
expectEqual(destPtr[1], 0x10)
expectEqual(destPtr[2], 0x11)
expectEqual(destPtr[3], 0x12)
expectEqual(destPtr[4], 0x13)
expectEqual(destPtr[5], 0x14)

// Copy from offset 5. Skips the first region and the first byte of the second
dispatchData.copyBytes(to: destPtr, from: 5..<11)
expectEqual(destPtr[0], 0x11)
expectEqual(destPtr[1], 0x12)
expectEqual(destPtr[2], 0x13)
expectEqual(destPtr[3], 0x14)
expectEqual(destPtr[4], 0x15)
expectEqual(destPtr[5], 0x16)

// Copy from offset 8. Skips the first two regions
destPtr[3] = 0xFF
destPtr[4] = 0xFF
destPtr[5] = 0xFF
dispatchData.copyBytes(to: destPtr, from: 8..<11)
expectEqual(destPtr[0], 0x14)
expectEqual(destPtr[1], 0x15)
expectEqual(destPtr[2], 0x16)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)

// Copy from offset 9. Skips the first two regions and the first byte of the third
destPtr[2] = 0xFF
destPtr[3] = 0xFF
destPtr[4] = 0xFF
destPtr[5] = 0xFF
dispatchData.copyBytes(to: destPtr, from: 9..<11)
expectEqual(destPtr[0], 0x15)
expectEqual(destPtr[1], 0x16)
expectEqual(destPtr[2], 0xFF)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)

// Copy from offset 9, but only 1 byte. Ends before the end of the data
destPtr[1] = 0xFF
destPtr[2] = 0xFF
destPtr[3] = 0xFF
destPtr[4] = 0xFF
destPtr[5] = 0xFF
dispatchData.copyBytes(to: destPtr, from: 9..<10)
expectEqual(destPtr[0], 0x15)
expectEqual(destPtr[1], 0xFF)
expectEqual(destPtr[2], 0xFF)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)

// Copy from offset 2, but only 1 byte. This copy is bounded within the
// first region.
destPtr[1] = 0xFF
destPtr[2] = 0xFF
destPtr[3] = 0xFF
destPtr[4] = 0xFF
destPtr[5] = 0xFF
dispatchData.copyBytes(to: destPtr, from: 2..<3)
expectEqual(destPtr[0], 2)
expectEqual(destPtr[1], 0xFF)
expectEqual(destPtr[2], 0xFF)
expectEqual(destPtr[3], 0xFF)
expectEqual(destPtr[4], 0xFF)
expectEqual(destPtr[5], 0xFF)
}

DispatchAPI.test("DispatchData.buffers") {
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
var ptr = UnsafeBufferPointer<UInt8>(start: bytes, count: bytes.count)
Expand All @@ -301,3 +428,26 @@ DispatchAPI.test("DispatchData.buffers") {
expectEqual(data.count, 0)
}

DispatchAPI.test("DispatchData.bufferUnsafeRawBufferPointer") {
let bytes = [UInt8(0), UInt8(1), UInt8(2), UInt8(2)]
var ptr = UnsafeRawBufferPointer(start: bytes, count: bytes.count)
var data = DispatchData(bytes: ptr)
expectEqual(bytes.count, data.count)
for i in 0..<data.count {
expectEqual(data[i], bytes[i])
}

data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
expectEqual(bytes.count, data.count)
for i in 0..<data.count {
expectEqual(data[i], bytes[i])
}

ptr = UnsafeRawBufferPointer(start: nil, count: 0)
data = DispatchData(bytes: ptr)
expectEqual(data.count, 0)

data = DispatchData(bytesNoCopy: ptr, deallocator: .custom(nil, {}))
expectEqual(data.count, 0)
}