]> git.saurik.com Git - apple/libdispatch.git/blob - src/swift/Data.swift
libdispatch-913.1.6.tar.gz
[apple/libdispatch.git] / src / swift / Data.swift
1 //===----------------------------------------------------------------------===//
2 //
3 // This source file is part of the Swift.org open source project
4 //
5 // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
6 // Licensed under Apache License v2.0 with Runtime Library Exception
7 //
8 // See http://swift.org/LICENSE.txt for license information
9 // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10 //
11 //===----------------------------------------------------------------------===//
12
13 import CDispatch
14
15 public struct DispatchData : RandomAccessCollection {
16 public typealias Iterator = DispatchDataIterator
17 public typealias Index = Int
18 public typealias Indices = DefaultRandomAccessIndices<DispatchData>
19
20 public static let empty: DispatchData = DispatchData(data: _swift_dispatch_data_empty())
21
22 public enum Deallocator {
23 /// Use `free`
24 case free
25
26 /// Use `munmap`
27 case unmap
28
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)
37
38 fileprivate var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
39 switch self {
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)
43 }
44 }
45 }
46
47 internal var __wrapped: __DispatchData
48
49 /// Initialize a `Data` with copied memory content.
50 ///
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())
57 self.init(data: d)
58 }
59
60 /// Initialize a `Data` with copied memory content.
61 ///
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())
68 self.init(data: d)
69 }
70
71 /// Initialize a `Data` without copying the bytes.
72 ///
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)
80 self.init(data: d)
81 }
82
83 /// Initialize a `Data` without copying the bytes.
84 ///
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)
92 self.init(data: d)
93 }
94
95 internal init(data: dispatch_data_t) {
96 __wrapped = __DispatchData(data: data, owned: true)
97 }
98
99 internal init(borrowedData: dispatch_data_t) {
100 __wrapped = __DispatchData(data: borrowedData, owned: false)
101 }
102
103 public var count: Int {
104 return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
105 }
106
107 public func withUnsafeBytes<Result, ContentType>(
108 body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
109 {
110 var ptr: UnsafeRawPointer? = nil
111 var size = 0
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)
117 }
118
119 public func enumerateBytes(
120 block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
121 {
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)
130 var stop = false
131 escapableBlock(bp, offset, &stop)
132 return !stop
133 }
134 }
135 }
136
137 /// Append bytes to the data.
138 ///
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))
145 }
146
147 /// Append bytes to the data.
148 ///
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))
156 }
157
158 /// Append data to the data.
159 ///
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)
164 }
165
166 /// Append a buffer of bytes to the data.
167 ///
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)
173 }
174 }
175
176 private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange<Index>) {
177 var copiedCount = 0
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)
186 copiedCount += count
187 return copiedCount < rangeSize
188 }
189 }
190
191 /// Copy the contents of the data to a pointer.
192 ///
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)
199 }
200
201 /// Copy the contents of the data to a pointer.
202 ///
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)
210 }
211
212 /// Copy a subset of the contents of the data to a pointer.
213 ///
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)
220 }
221
222 /// Copy a subset of the contents of the data to a pointer.
223 ///
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)
231 }
232
233 /// Copy the contents of the data into a buffer.
234 ///
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 {
241 let cnt = count
242 guard cnt > 0 else { return 0 }
243
244 let copyRange : CountableRange<Index>
245 if let r = range {
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")
249
250 precondition(r.endIndex >= 0)
251 precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
252
253 copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
254 } else {
255 copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
256 }
257
258 guard !copyRange.isEmpty else { return 0 }
259
260 _copyBytesHelper(to: buffer.baseAddress!, from: copyRange)
261 return copyRange.count
262 }
263
264 /// Sets or returns the byte at the specified index.
265 public subscript(index: Index) -> UInt8 {
266 var offset = 0
267 let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
268
269 var ptr: UnsafeRawPointer? = nil
270 var size = 0
271 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
272 defer { _fixLifetime(map) }
273
274 return ptr!.load(fromByteOffset: index - offset, as: UInt8.self)
275 }
276
277 public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
278 return RandomAccessSlice(base: self, bounds: bounds)
279 }
280
281 /// Return a new copy of the data in a specified range.
282 ///
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)
288 }
289
290 public func region(location: Int) -> (data: DispatchData, offset: Int) {
291 var offset: Int = 0
292 let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
293 return (DispatchData(data: data), offset)
294 }
295
296 public var startIndex: Index {
297 return 0
298 }
299
300 public var endIndex: Index {
301 return count
302 }
303
304 public func index(before i: Index) -> Index {
305 return i - 1
306 }
307
308 public func index(after i: Index) -> Index {
309 return i + 1
310 }
311
312 /// An iterator over the contents of the data.
313 ///
314 /// The iterator will increment byte-by-byte.
315 public func makeIterator() -> DispatchData.Iterator {
316 return DispatchDataIterator(_data: self)
317 }
318 }
319
320 public struct DispatchDataIterator : IteratorProtocol, Sequence {
321
322 /// Create an iterator over the given DispatchData
323 public init(_data: DispatchData) {
324 var ptr: UnsafeRawPointer?
325 self._count = 0
326 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true)
327 self._ptr = ptr
328 self._position = _data.startIndex
329
330 // The only time we expect a 'nil' pointer is when the data is empty.
331 assert(self._ptr != nil || self._count == self._position)
332 }
333
334 /// Advance to the next element and return it, or `nil` if no next
335 /// element exists.
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
340 return element
341 }
342
343 internal let _data: __DispatchData
344 internal var _ptr: UnsafeRawPointer!
345 internal var _count: Int
346 internal var _position: DispatchData.Index
347 }
348
349 @_silgen_name("_swift_dispatch_data_empty")
350 internal func _swift_dispatch_data_empty() -> dispatch_data_t
351
352 @_silgen_name("_swift_dispatch_data_destructor_free")
353 internal func _dispatch_data_destructor_free() -> _DispatchBlock
354
355 @_silgen_name("_swift_dispatch_data_destructor_munmap")
356 internal func _dispatch_data_destructor_munmap() -> _DispatchBlock
357
358 @_silgen_name("_swift_dispatch_data_destructor_default")
359 internal func _dispatch_data_destructor_default() -> _DispatchBlock