]> git.saurik.com Git - apple/libdispatch.git/blobdiff - src/swift/Data.swift
libdispatch-913.30.4.tar.gz
[apple/libdispatch.git] / src / swift / Data.swift
index 0d21e27c048612680d0e0e70beede6c73562404c..1e7350463e9532181bfe22e3b0ca8f488993c36b 100644 (file)
@@ -19,7 +19,6 @@ public struct DispatchData : RandomAccessCollection {
 
        public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty())
 
-#if false /* FIXME: dragging in _TMBO (Objective-C) */
        public enum Deallocator {
                /// Use `free`
                case free
@@ -28,9 +27,15 @@ public struct DispatchData : RandomAccessCollection {
                case unmap
 
                /// A custom deallocator
-               case custom(DispatchQueue?, @convention(block) () -> Void)
-
-               private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
+               // FIXME: Want @convention(block) here to minimize the overhead of
+               //        doing the conversion (once per custom enum instance instead
+               //        of once per call to DispatchData.init using the enum instance).
+               //        However, adding the annotation here results in Data.o containing
+               //        a reference to _TMBO (opaque metadata for Builtin.UnknownObject)
+               //        which is only made available on platforms with Objective-C.
+               case custom(DispatchQueue?, () -> Void)
+
+               fileprivate var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
                        switch self {
                        case .free: return (nil, _dispatch_data_destructor_free())
                        case .unmap: return (nil, _dispatch_data_destructor_munmap())
@@ -38,55 +43,94 @@ public struct DispatchData : RandomAccessCollection {
                        }
                }
        }
-#endif
-       internal var __wrapped: dispatch_data_t
+
+       internal var __wrapped: __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.
+       @available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer) instead")
        public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
-               __wrapped = dispatch_data_create(
-                       buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
+               let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
+                                       : dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
+                                                       _dispatch_data_destructor_default())
+               self.init(data: d)
+       }
+
+       /// 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) {
+               let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
+                                       : dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
+                                                       _dispatch_data_destructor_default())
+               self.init(data: d)
        }
-#if false /* FIXME: dragging in _TMBO (Objective-C) */
+
        /// Initialize a `Data` without copying the bytes.
        ///
-       /// - parameter bytes: A pointer to the bytes.
-       /// - parameter count: The size of the bytes.
+       /// - parameter bytes: A buffer pointer containing the data.
        /// - 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
+               let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
+                                       : dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
+               self.init(data: d)
+       }
 
-               __wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
+       /// 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
+               let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
+                                       : dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
+               self.init(data: d)
        }
-#endif
+
        internal init(data: dispatch_data_t) {
-               __wrapped = data
+               __wrapped = __DispatchData(data: data, owned: true)
+       }
+
+       internal init(borrowedData: dispatch_data_t) {
+               __wrapped = __DispatchData(data: borrowedData, owned: false)
        }
 
        public var count: Int {
-               return CDispatch.dispatch_data_get_size(__wrapped)
+               return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
        }
 
        public func withUnsafeBytes<Result, ContentType>(
-               body: @noescape (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
+               body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
        {
-               var ptr: UnsafePointer<Void>? = nil
-               var size = 0;
-               let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size)
+               var ptr: UnsafeRawPointer? = nil
+               var size = 0
+               let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size)
+               let contentPtr = ptr!.bindMemory(
+                       to: ContentType.self, capacity: size / MemoryLayout<ContentType>.stride)
                defer { _fixLifetime(data) }
-               return try body(UnsafePointer<ContentType>(ptr!))
+               return try body(contentPtr)
        }
 
        public func enumerateBytes(
-               block: @noescape (buffer: UnsafeBufferPointer<UInt8>, byteIndex: Int, stop: inout Bool) -> Void) 
+               block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
        {
-               _swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
-                       let bp = UnsafeBufferPointer(start: UnsafePointer<UInt8>(ptr), count: size)
-                       var stop = false
-                       block(buffer: bp, byteIndex: offset, stop: &stop)
-                       return !stop
+               // we know that capturing block in the closure being created/passed to dispatch_data_apply
+               // does not cause block to escape because dispatch_data_apply does not allow its
+               // block argument to escape.  Therefore, the usage of withoutActuallyEscaping to
+               // bypass the Swift type system is safe.
+               withoutActuallyEscaping(block) { escapableBlock in
+                       _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
+                               let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size)
+                               let bp = UnsafeBufferPointer(start: bytePtr, count: size)
+                               var stop = false
+                               escapableBlock(bp, offset, &stop)
+                               return !stop
+                       }
                }
        }
 
@@ -94,33 +138,53 @@ public struct DispatchData : RandomAccessCollection {
        ///
        /// - 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 = dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default())
                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 = dispatch_data_create(bytes.baseAddress!, bytes.count, nil, _dispatch_data_destructor_default())
+               self.append(DispatchData(data: data))
+       }
+
        /// Append data to the data.
        ///
        /// - parameter data: The data to append to this data.
        public mutating func append(_ other: DispatchData) {
-               let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped)
-               __wrapped = data
+               let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped)
+               __wrapped = __DispatchData(data: data, owned: true)
        }
 
        /// Append a buffer of bytes to the data.
        ///
        /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`.
        public mutating func append<SourceType>(_ buffer : UnsafeBufferPointer<SourceType>) {
-               self.append(UnsafePointer(buffer.baseAddress!), count: buffer.count * sizeof(SourceType.self))
+               let count = buffer.count * MemoryLayout<SourceType>.stride;
+               buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: count) {
+                       self.append($0, count: count)
+               }
        }
 
-       private func _copyBytesHelper(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
+       private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange<Index>) {
                var copiedCount = 0
-               _ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
-                       let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size)
-                       memcpy(pointer + copiedCount, ptr, limit)
-                       copiedCount += limit
-                       return copiedCount < (range.endIndex - range.startIndex)
+               if range.isEmpty { return }
+               let rangeSize = range.count
+               _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in
+                       if offset >= range.endIndex { return false } // This region is after endIndex
+                       let copyOffset = range.startIndex > offset ? range.startIndex - offset : 0 // offset of first byte, in this region
+                       if copyOffset >= size { return true } // This region is before startIndex
+                       let count = Swift.min(rangeSize - copiedCount, size - copyOffset)
+                       memcpy(pointer + copiedCount, ptr + copyOffset, count)
+                       copiedCount += count
+                       return copiedCount < rangeSize
                }
        }
 
@@ -129,22 +193,46 @@ public struct DispatchData : RandomAccessCollection {
        /// - 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 `sizeof(DestinationType) * buffer.count` then the first N bytes will be copied into the 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.
        /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
        /// - parameter buffer: A buffer to copy the data into.
        /// - parameter range: A range in the data to copy into the buffer. If the range is empty, this function will return 0 without copying anything. If the range is nil, as much data as will fit into `buffer` is copied.
@@ -162,30 +250,28 @@ public struct DispatchData : RandomAccessCollection {
                        precondition(r.endIndex >= 0)
                        precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
                        
-                       copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * sizeof(DestinationType.self), r.count))
+                       copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
                } else {
-                       copyRange = 0..<Swift.min(buffer.count * sizeof(DestinationType.self), cnt)
+                       copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
                }
                
                guard !copyRange.isEmpty else { return 0 }
                
-               let pointer : UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>(buffer.baseAddress!)
-               _copyBytesHelper(to: pointer, from: copyRange)
+               _copyBytesHelper(to: buffer.baseAddress!, from: copyRange)
                return copyRange.count
        }
 
        /// Sets or returns the byte at the specified index.
        public subscript(index: Index) -> UInt8 {
                var offset = 0
-               let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset)
+               let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
 
-               var ptr: UnsafePointer<Void>? = nil
+               var ptr: UnsafeRawPointer? = nil
                var size = 0
                let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
                defer { _fixLifetime(map) }
 
-               let pptr = UnsafePointer<UInt8>(ptr!)
-               return pptr[index - offset]
+               return ptr!.load(fromByteOffset: index - offset, as: UInt8.self)
        }
 
        public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
@@ -197,13 +283,13 @@ public struct DispatchData : RandomAccessCollection {
        /// - parameter range: The range to copy.
        public func subdata(in range: CountableRange<Index>) -> DispatchData {
                let subrange = CDispatch.dispatch_data_create_subrange(
-                       __wrapped, range.startIndex, range.endIndex - range.startIndex)
+                       __wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex)
                return DispatchData(data: subrange)
        }
 
        public func region(location: Int) -> (data: DispatchData, offset: Int) {
                var offset: Int = 0
-               let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset)
+               let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
                return (DispatchData(data: data), offset)
        }
 
@@ -233,37 +319,33 @@ public struct DispatchData : RandomAccessCollection {
 
 public struct DispatchDataIterator : IteratorProtocol, Sequence {
 
-       /// Create an iterator over the given DisaptchData
+       /// Create an iterator over the given DispatchData
        public init(_data: DispatchData) {
-               var ptr: UnsafePointer<Void>?
+               var ptr: UnsafeRawPointer?
                self._count = 0
-               self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count)
-               self._ptr = UnsafePointer(ptr!)
+               self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true)
+               self._ptr = ptr
                self._position = _data.startIndex
+
+               // The only time we expect a 'nil' pointer is when the data is empty.
+               assert(self._ptr != nil || self._count == self._position)
        }
 
        /// Advance to the next element and return it, or `nil` if no next
        /// element exists.
-       ///
-       /// - Precondition: No preceding call to `self.next()` has returned `nil`.
        public mutating func next() -> DispatchData._Element? {
                if _position == _count { return nil }
-               let element = _ptr[_position];
+               let element = _ptr.load(fromByteOffset: _position, as: UInt8.self)
                _position = _position + 1
                return element
        }
 
-       internal let _data: dispatch_data_t
-       internal var _ptr: UnsafePointer<UInt8>
+       internal let _data: __DispatchData
+       internal var _ptr: UnsafeRawPointer!
        internal var _count: Int
        internal var _position: DispatchData.Index
 }
 
-typealias _swift_data_applier = @convention(block) @noescape (dispatch_data_t, Int, UnsafePointer<Void>, Int) -> Bool
-
-@_silgen_name("_swift_dispatch_data_apply")
-internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier)
-
 @_silgen_name("_swift_dispatch_data_empty")
 internal func _swift_dispatch_data_empty() -> dispatch_data_t