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