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 public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
53 let d = dispatch_data_create(buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
57 /// Initialize a `Data` without copying the bytes.
59 /// - parameter bytes: A buffer pointer containing the data.
60 /// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
61 public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
62 let (q, b) = deallocator._deallocator
63 let d = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
67 internal init(data: dispatch_data_t) {
68 __wrapped = __DispatchData(data: data, owned: true)
71 internal init(borrowedData: dispatch_data_t) {
72 __wrapped = __DispatchData(data: borrowedData, owned: false)
75 public var count: Int {
76 return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
79 public func withUnsafeBytes<Result, ContentType>(
80 body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
82 var ptr: UnsafeRawPointer? = nil
84 let data = CDispatch.dispatch_data_create_map(__wrapped.__wrapped, &ptr, &size)
85 let contentPtr = ptr!.bindMemory(
86 to: ContentType.self, capacity: size / MemoryLayout<ContentType>.stride)
87 defer { _fixLifetime(data) }
88 return try body(contentPtr)
91 public func enumerateBytes(
92 block: @noescape (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
94 _swift_dispatch_data_apply(__wrapped.__wrapped) { (_, offset: Int, ptr: UnsafeRawPointer, size: Int) in
95 let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: size)
96 let bp = UnsafeBufferPointer(start: bytePtr, count: size)
98 block(bp, offset, &stop)
103 /// Append bytes to the data.
105 /// - parameter bytes: A pointer to the bytes to copy in to the data.
106 /// - parameter count: The number of bytes to copy.
107 public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
108 let data = dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default())
109 self.append(DispatchData(data: data))
112 /// Append data to the data.
114 /// - parameter data: The data to append to this data.
115 public mutating func append(_ other: DispatchData) {
116 let data = CDispatch.dispatch_data_create_concat(__wrapped.__wrapped, other.__wrapped.__wrapped)
117 __wrapped = __DispatchData(data: data, owned: true)
120 /// Append a buffer of bytes to the data.
122 /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`.
123 public mutating func append<SourceType>(_ buffer : UnsafeBufferPointer<SourceType>) {
124 let count = buffer.count * sizeof(SourceType.self)
125 buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: count) {
126 self.append($0, count: count)
130 private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange<Index>) {
132 _ = CDispatch.dispatch_data_apply(__wrapped.__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafeRawPointer, size: Int) in
133 let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size)
134 memcpy(pointer + copiedCount, ptr, limit)
136 return copiedCount < (range.endIndex - range.startIndex)
140 /// Copy the contents of the data to a pointer.
142 /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
143 /// - parameter count: The number of bytes to copy.
144 /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
145 public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
146 _copyBytesHelper(to: pointer, from: 0..<count)
149 /// Copy a subset of the contents of the data to a pointer.
151 /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
152 /// - parameter range: The range in the `Data` to copy.
153 /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
154 public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
155 _copyBytesHelper(to: pointer, from: range)
158 /// Copy the contents of the data into a buffer.
160 /// 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.
161 /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
162 /// - parameter buffer: A buffer to copy the data into.
163 /// - 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.
164 /// - returns: Number of bytes copied into the destination buffer.
165 public func copyBytes<DestinationType>(to buffer: UnsafeMutableBufferPointer<DestinationType>, from range: CountableRange<Index>? = nil) -> Int {
167 guard cnt > 0 else { return 0 }
169 let copyRange : CountableRange<Index>
171 guard !r.isEmpty else { return 0 }
172 precondition(r.startIndex >= 0)
173 precondition(r.startIndex < cnt, "The range is outside the bounds of the data")
175 precondition(r.endIndex >= 0)
176 precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
178 copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
180 copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
183 guard !copyRange.isEmpty else { return 0 }
185 let bufferCapacity = buffer.count * sizeof(DestinationType.self)
186 buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: bufferCapacity) {
187 _copyBytesHelper(to: $0, from: copyRange)
189 return copyRange.count
192 /// Sets or returns the byte at the specified index.
193 public subscript(index: Index) -> UInt8 {
195 let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
197 var ptr: UnsafeRawPointer? = nil
199 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
200 defer { _fixLifetime(map) }
202 return ptr!.load(fromByteOffset: index - offset, as: UInt8.self)
205 public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
206 return RandomAccessSlice(base: self, bounds: bounds)
209 /// Return a new copy of the data in a specified range.
211 /// - parameter range: The range to copy.
212 public func subdata(in range: CountableRange<Index>) -> DispatchData {
213 let subrange = CDispatch.dispatch_data_create_subrange(
214 __wrapped.__wrapped, range.startIndex, range.endIndex - range.startIndex)
215 return DispatchData(data: subrange)
218 public func region(location: Int) -> (data: DispatchData, offset: Int) {
220 let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
221 return (DispatchData(data: data), offset)
224 public var startIndex: Index {
228 public var endIndex: Index {
232 public func index(before i: Index) -> Index {
236 public func index(after i: Index) -> Index {
240 /// An iterator over the contents of the data.
242 /// The iterator will increment byte-by-byte.
243 public func makeIterator() -> DispatchData.Iterator {
244 return DispatchDataIterator(_data: self)
248 public struct DispatchDataIterator : IteratorProtocol, Sequence {
250 /// Create an iterator over the given DispatchData
251 public init(_data: DispatchData) {
252 var ptr: UnsafeRawPointer?
254 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true)
256 self._position = _data.startIndex
258 // The only time we expect a 'nil' pointer is when the data is empty.
259 assert(self._ptr != nil || self._count == self._position)
262 /// Advance to the next element and return it, or `nil` if no next
264 public mutating func next() -> DispatchData._Element? {
265 if _position == _count { return nil }
266 let element = _ptr.load(fromByteOffset: _position, as: UInt8.self)
267 _position = _position + 1
271 internal let _data: __DispatchData
272 internal var _ptr: UnsafeRawPointer!
273 internal var _count: Int
274 internal var _position: DispatchData.Index
277 typealias _swift_data_applier = @convention(block) (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool
279 @_silgen_name("_swift_dispatch_data_apply")
280 internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier)
282 @_silgen_name("_swift_dispatch_data_empty")
283 internal func _swift_dispatch_data_empty() -> dispatch_data_t
285 @_silgen_name("_swift_dispatch_data_destructor_free")
286 internal func _dispatch_data_destructor_free() -> _DispatchBlock
288 @_silgen_name("_swift_dispatch_data_destructor_munmap")
289 internal func _dispatch_data_destructor_munmap() -> _DispatchBlock
291 @_silgen_name("_swift_dispatch_data_destructor_default")
292 internal func _dispatch_data_destructor_default() -> _DispatchBlock