From 8730836fea72937fd64eb8ee572ad63fa5427b91 Mon Sep 17 00:00:00 2001 From: Kim Topley Date: Wed, 8 Mar 2017 16:52:02 -0800 Subject: [PATCH 1/2] Add support for UnsafeRawBufferPointer to DispatchData (Radar 28503167) --- stdlib/public/SDK/Dispatch/Data.swift | 57 ++++++++++ test/stdlib/Dispatch.swift | 153 +++++++++++++++++++++++++- 2 files changed, 209 insertions(+), 1 deletion(-) diff --git a/stdlib/public/SDK/Dispatch/Data.swift b/stdlib/public/SDK/Dispatch/Data.swift index a6b9aa2667f67..c6ee0d14fee00 100644 --- a/stdlib/public/SDK/Dispatch/Data.swift +++ b/stdlib/public/SDK/Dispatch/Data.swift @@ -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) { __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(bytes: UnsafeRawBufferPointer, deallocater: Deallocator) instead") public init(bytesNoCopy bytes: UnsafeBufferPointer, 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 } @@ -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, 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. @@ -139,19 +174,41 @@ 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, count: Int) { _copyBytesHelper(to: pointer, from: 0..) instead") public func copyBytes(to pointer: UnsafeMutablePointer, from range: CountableRange) { _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. + /// - 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. + public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange) { + 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.stride * buffer.count` then the first N bytes will be copied into the buffer. diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index 76e41317451ae..ac1b33f3ce34c 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -76,7 +76,7 @@ DispatchAPI.test("dispatch_data_t deallocator") { autoreleasepool { let size = 1024 let p = UnsafeMutablePointer.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 })) } @@ -278,6 +278,134 @@ 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(start: bytes, count: bytes.count) @@ -301,3 +429,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.. Date: Fri, 10 Mar 2017 11:01:34 -0800 Subject: [PATCH 2/2] Review comments. --- stdlib/public/SDK/Dispatch/Data.swift | 12 +++++++----- test/stdlib/Dispatch.swift | 1 - 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/stdlib/public/SDK/Dispatch/Data.swift b/stdlib/public/SDK/Dispatch/Data.swift index c6ee0d14fee00..b419d7f0f10b8 100644 --- a/stdlib/public/SDK/Dispatch/Data.swift +++ b/stdlib/public/SDK/Dispatch/Data.swift @@ -66,7 +66,7 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// - 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(bytes: UnsafeRawBufferPointer, deallocater: Deallocator) instead") + @available(swift, deprecated: 4, message: "Use init(bytesNoCopy: UnsafeRawBufferPointer, deallocater: Deallocator) instead") public init(bytesNoCopy bytes: UnsafeBufferPointer, deallocator: Deallocator = .free) { let (q, b) = deallocator._deallocator __wrapped = bytes.baseAddress == nil ? _swift_dispatch_data_empty() @@ -181,10 +181,11 @@ public struct DispatchData : RandomAccessCollection, _ObjectiveCBridgeable { /// Copy the contents of the data to a pointer. /// - /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. + /// - 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. - /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes. 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..) { + 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) } diff --git a/test/stdlib/Dispatch.swift b/test/stdlib/Dispatch.swift index ac1b33f3ce34c..2fe182e172bfe 100644 --- a/test/stdlib/Dispatch.swift +++ b/test/stdlib/Dispatch.swift @@ -285,7 +285,6 @@ DispatchAPI.test("DispatchData.copyBytesUnsafeRawBufferPointer") { 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