1 //===----------------------------------------------------------------------===//
 
   3 // This source file is part of the Swift.org open source project
 
   5 // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
 
   6 // Licensed under Apache License v2.0 with Runtime Library Exception
 
   8 // See http://swift.org/LICENSE.txt for license information
 
   9 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
 
  11 //===----------------------------------------------------------------------===//
 
  15 public struct DispatchData : RandomAccessCollection {
 
  16         public typealias Iterator = DispatchDataIterator
 
  17         public typealias Index = Int
 
  18         public typealias Indices = DefaultRandomAccessIndices<DispatchData>
 
  20         public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty())
 
  22         public enum Deallocator {
 
  29                 /// A custom deallocator
 
  30                 // FIXME: Want @convention(block) here to minimize the overhead of
 
  31                 //        doing the conversion (once per custom enum instance instead
 
  32                 //        of once per call to DispatchData.init using the enum instance).
 
  33                 //        However, adding the annotation here results in Data.o containing
 
  34                 //        a reference to _TMBO (opaque metadata for Builtin.UnknownObject)
 
  35                 //        which is only made available on platforms with Objective-C.
 
  36                 case custom(DispatchQueue?, () -> Void)
 
  38                 fileprivate var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
 
  40                         case .free: return (nil, _dispatch_data_destructor_free())
 
  41                         case .unmap: return (nil, _dispatch_data_destructor_munmap())
 
  42                         case .custom(let q, let b): return (q, b)
 
  47         internal var __wrapped: __DispatchData
 
  49         /// Initialize a `Data` with copied memory content.
 
  51         /// - parameter bytes: A pointer to the memory. It will be copied.
 
  52         @available(swift, deprecated: 4, message: "Use init(bytes: UnsafeRawBufferPointer) instead")
 
  53         public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
 
  54                 let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
 
  55                                         : dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
 
  56                                                         _dispatch_data_destructor_default())
 
  60         /// Initialize a `Data` with copied memory content.
 
  62         /// - parameter bytes: A pointer to the memory. It will be copied.
 
  63         /// - parameter count: The number of bytes to copy.
 
  64         public init(bytes buffer: UnsafeRawBufferPointer) {
 
  65                 let d = buffer.baseAddress == nil ? _swift_dispatch_data_empty()
 
  66                                         : dispatch_data_create(buffer.baseAddress!, buffer.count, nil,
 
  67                                                         _dispatch_data_destructor_default())
 
  71         /// Initialize a `Data` without copying the bytes.
 
  73         /// - parameter bytes: A buffer pointer containing the data.
 
  74         /// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
 
  75         @available(swift, deprecated: 4, message: "Use init(bytesNoCopy: UnsafeRawBufferPointer, deallocater: Deallocator) instead")
 
  76         public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
 
  77                 let (q, b) = deallocator._deallocator
 
  78                 let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
 
  79                                         : dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
 
  83         /// Initialize a `Data` without copying the bytes.
 
  85         /// - parameter bytes: A pointer to the bytes.
 
  86         /// - parameter count: The size of the bytes.
 
  87         /// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
 
  88         public init(bytesNoCopy bytes: UnsafeRawBufferPointer, deallocator: Deallocator = .free) {
 
  89                 let (q, b) = deallocator._deallocator
 
  90                 let d = bytes.baseAddress == nil ? _swift_dispatch_data_empty()
 
  91                                         : dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
 
  95         internal init(data: dispatch_data_t) {
 
  96                 __wrapped = __DispatchData(data: data, owned: true)
 
  99         internal init(borrowedData: dispatch_data_t) {
 
 100                 __wrapped = __DispatchData(data: borrowedData, owned: false)
 
 103         public var count: Int {
 
 104                 return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
 
 107         public func withUnsafeBytes<Result, ContentType>(
 
 108                 body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
 
 110                 var ptr: UnsafeRawPointer? = nil
 
 112                 let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size)
 
 113                 let contentPtr = ptr!.bindMemory(
 
 114                         to: ContentType.self, capacity: size / MemoryLayout<ContentType>.stride)
 
 115                 defer { _fixLifetime(data) }
 
 116                 return try body(contentPtr)
 
 119         public func enumerateBytes(
 
 120                 block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
 
 122                 // we know that capturing block in the closure being created/passed to dispatch_data_apply
 
 123                 // does not cause block to escape because dispatch_data_apply does not allow its
 
 124                 // block argument to escape.  Therefore, the usage of withoutActuallyEscaping to
 
 125                 // bypass the Swift type system is safe.
 
 126                 withoutActuallyEscaping(block) { escapableBlock in
 
 127                         _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
 
 128                                 let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size)
 
 129                                 let bp = UnsafeBufferPointer(start: bytePtr, count: size)
 
 131                                 escapableBlock(bp, offset, &stop)
 
 137         /// Append bytes to the data.
 
 139         /// - parameter bytes: A pointer to the bytes to copy in to the data.
 
 140         /// - parameter count: The number of bytes to copy.
 
 141         @available(swift, deprecated: 4, message: "Use append(_: UnsafeRawBufferPointer) instead")
 
 142         public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
 
 143                 let data = dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default())
 
 144                 self.append(DispatchData(data: data))
 
 147         /// Append bytes to the data.
 
 149         /// - parameter bytes: A pointer to the bytes to copy in to the data.
 
 150         /// - parameter count: The number of bytes to copy.
 
 151         public mutating func append(_ bytes: UnsafeRawBufferPointer) {
 
 152                 // Nil base address does nothing.
 
 153                 guard bytes.baseAddress != nil else { return }
 
 154                 let data = dispatch_data_create(bytes.baseAddress!, bytes.count, nil, _dispatch_data_destructor_default())
 
 155                 self.append(DispatchData(data: data))
 
 158         /// Append data to the data.
 
 160         /// - parameter data: The data to append to this data.
 
 161         public mutating func append(_ other: DispatchData) {
 
 162                 let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped)
 
 163                 __wrapped = __DispatchData(data: data, owned: true)
 
 166         /// Append a buffer of bytes to the data.
 
 168         /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`.
 
 169         public mutating func append<SourceType>(_ buffer : UnsafeBufferPointer<SourceType>) {
 
 170                 let count = buffer.count * MemoryLayout<SourceType>.stride;
 
 171                 buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: count) {
 
 172                         self.append($0, count: count)
 
 176         private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange<Index>) {
 
 178                 if range.isEmpty { return }
 
 179                 let rangeSize = range.count
 
 180                 _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in
 
 181                         if offset >= range.endIndex { return false } // This region is after endIndex
 
 182                         let copyOffset = range.startIndex > offset ? range.startIndex - offset : 0 // offset of first byte, in this region
 
 183                         if copyOffset >= size { return true } // This region is before startIndex
 
 184                         let count = Swift.min(rangeSize - copiedCount, size - copyOffset)
 
 185                         memcpy(pointer + copiedCount, ptr + copyOffset, count)
 
 187                         return copiedCount < rangeSize
 
 191         /// Copy the contents of the data to a pointer.
 
 193         /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
 
 194         /// - parameter count: The number of bytes to copy.
 
 195         /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
 
 196         @available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, count: Int) instead")
 
 197         public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
 
 198                 _copyBytesHelper(to: pointer, from: 0..<count)
 
 201         /// Copy the contents of the data to a pointer.
 
 203         /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
 
 204         ///     enough to hold `count` bytes.
 
 205         /// - parameter count: The number of bytes to copy.
 
 206         public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, count: Int) {
 
 207                 assert(count <= pointer.count, "Buffer too small to copy \(count) bytes")
 
 208                 guard pointer.baseAddress != nil else { return }
 
 209                 _copyBytesHelper(to: pointer.baseAddress!, from: 0..<count)
 
 212         /// Copy a subset of the contents of the data to a pointer.
 
 214         /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
 
 215         /// - parameter range: The range in the `Data` to copy.
 
 216         /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
 
 217         @available(swift, deprecated: 4, message: "Use copyBytes(to: UnsafeMutableRawBufferPointer, from: CountableRange<Index>) instead")
 
 218         public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
 
 219                 _copyBytesHelper(to: pointer, from: range)
 
 222         /// Copy a subset of the contents of the data to a pointer.
 
 224         /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into. The buffer must be large
 
 225         ///     enough to hold `count` bytes.
 
 226         /// - parameter range: The range in the `Data` to copy.
 
 227         public func copyBytes(to pointer: UnsafeMutableRawBufferPointer, from range: CountableRange<Index>) {
 
 228                 assert(range.count <= pointer.count, "Buffer too small to copy \(range.count) bytes")
 
 229                 guard pointer.baseAddress != nil else { return }
 
 230                 _copyBytesHelper(to: pointer.baseAddress!, from: range)
 
 233         /// Copy the contents of the data into a buffer.
 
 235         /// 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.
 
 236         /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
 
 237         /// - parameter buffer: A buffer to copy the data into.
 
 238         /// - 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.
 
 239         /// - returns: Number of bytes copied into the destination buffer.
 
 240         public func copyBytes<DestinationType>(to buffer: UnsafeMutableBufferPointer<DestinationType>, from range: CountableRange<Index>? = nil) -> Int {
 
 242                 guard cnt > 0 else { return 0 }
 
 244                 let copyRange : CountableRange<Index>
 
 246                         guard !r.isEmpty else { return 0 }
 
 247                         precondition(r.startIndex >= 0)
 
 248                         precondition(r.startIndex < cnt, "The range is outside the bounds of the data")
 
 250                         precondition(r.endIndex >= 0)
 
 251                         precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
 
 253                         copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
 
 255                         copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
 
 258                 guard !copyRange.isEmpty else { return 0 }
 
 260                 _copyBytesHelper(to: buffer.baseAddress!, from: copyRange)
 
 261                 return copyRange.count
 
 264         /// Sets or returns the byte at the specified index.
 
 265         public subscript(index: Index) -> UInt8 {
 
 267                 let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
 
 269                 var ptr: UnsafeRawPointer? = nil
 
 271                 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
 
 272                 defer { _fixLifetime(map) }
 
 274                 return ptr!.load(fromByteOffset: index - offset, as: UInt8.self)
 
 277         public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
 
 278                 return RandomAccessSlice(base: self, bounds: bounds)
 
 281         /// Return a new copy of the data in a specified range.
 
 283         /// - parameter range: The range to copy.
 
 284         public func subdata(in range: CountableRange<Index>) -> DispatchData {
 
 285                 let subrange = CDispatch.dispatch_data_create_subrange(
 
 286                         __wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex)
 
 287                 return DispatchData(data: subrange)
 
 290         public func region(location: Int) -> (data: DispatchData, offset: Int) {
 
 292                 let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
 
 293                 return (DispatchData(data: data), offset)
 
 296         public var startIndex: Index {
 
 300         public var endIndex: Index {
 
 304         public func index(before i: Index) -> Index {
 
 308         public func index(after i: Index) -> Index {
 
 312         /// An iterator over the contents of the data.
 
 314         /// The iterator will increment byte-by-byte.
 
 315         public func makeIterator() -> DispatchData.Iterator {
 
 316                 return DispatchDataIterator(_data: self)
 
 320 public struct DispatchDataIterator : IteratorProtocol, Sequence {
 
 322         /// Create an iterator over the given DispatchData
 
 323         public init(_data: DispatchData) {
 
 324                 var ptr: UnsafeRawPointer?
 
 326                 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true)
 
 328                 self._position = _data.startIndex
 
 330                 // The only time we expect a 'nil' pointer is when the data is empty.
 
 331                 assert(self._ptr != nil || self._count == self._position)
 
 334         /// Advance to the next element and return it, or `nil` if no next
 
 336         public mutating func next() -> DispatchData._Element? {
 
 337                 if _position == _count { return nil }
 
 338                 let element = _ptr.load(fromByteOffset: _position, as: UInt8.self)
 
 339                 _position = _position + 1
 
 343         internal let _data: __DispatchData
 
 344         internal var _ptr: UnsafeRawPointer!
 
 345         internal var _count: Int
 
 346         internal var _position: DispatchData.Index
 
 349 @_silgen_name("_swift_dispatch_data_empty")
 
 350 internal func _swift_dispatch_data_empty() -> dispatch_data_t
 
 352 @_silgen_name("_swift_dispatch_data_destructor_free")
 
 353 internal func _dispatch_data_destructor_free() -> _DispatchBlock
 
 355 @_silgen_name("_swift_dispatch_data_destructor_munmap")
 
 356 internal func _dispatch_data_destructor_munmap() -> _DispatchBlock
 
 358 @_silgen_name("_swift_dispatch_data_destructor_default")
 
 359 internal func _dispatch_data_destructor_default() -> _DispatchBlock