]> git.saurik.com Git - apple/libdispatch.git/blob - src/swift/Data.swift
libdispatch-703.50.37.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 public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
53 let d = dispatch_data_create(buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
54 self.init(data: d)
55 }
56
57 /// Initialize a `Data` without copying the bytes.
58 ///
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)
64 self.init(data: d)
65 }
66
67 internal init(data: dispatch_data_t) {
68 __wrapped = __DispatchData(data: data, owned: true)
69 }
70
71 internal init(borrowedData: dispatch_data_t) {
72 __wrapped = __DispatchData(data: borrowedData, owned: false)
73 }
74
75 public var count: Int {
76 return CDispatch.dispatch_data_get_size(__wrapped.__wrapped)
77 }
78
79 public func withUnsafeBytes<Result, ContentType>(
80 body: (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
81 {
82 var ptr: UnsafeRawPointer? = nil
83 var size = 0
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)
89 }
90
91 public func enumerateBytes(
92 block: @noescape (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Int, _ stop: inout Bool) -> Void)
93 {
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)
97 var stop = false
98 block(bp, offset, &stop)
99 return !stop
100 }
101 }
102
103 /// Append bytes to the data.
104 ///
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))
110 }
111
112 /// Append data to the data.
113 ///
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)
118 }
119
120 /// Append a buffer of bytes to the data.
121 ///
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)
127 }
128 }
129
130 private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: CountableRange<Index>) {
131 var copiedCount = 0
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)
135 copiedCount += limit
136 return copiedCount < (range.endIndex - range.startIndex)
137 }
138 }
139
140 /// Copy the contents of the data to a pointer.
141 ///
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)
147 }
148
149 /// Copy a subset of the contents of the data to a pointer.
150 ///
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)
156 }
157
158 /// Copy the contents of the data into a buffer.
159 ///
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 {
166 let cnt = count
167 guard cnt > 0 else { return 0 }
168
169 let copyRange : CountableRange<Index>
170 if let r = range {
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")
174
175 precondition(r.endIndex >= 0)
176 precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
177
178 copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, r.count))
179 } else {
180 copyRange = 0..<Swift.min(buffer.count * MemoryLayout<DestinationType>.stride, cnt)
181 }
182
183 guard !copyRange.isEmpty else { return 0 }
184
185 let bufferCapacity = buffer.count * sizeof(DestinationType.self)
186 buffer.baseAddress?.withMemoryRebound(to: UInt8.self, capacity: bufferCapacity) {
187 _copyBytesHelper(to: $0, from: copyRange)
188 }
189 return copyRange.count
190 }
191
192 /// Sets or returns the byte at the specified index.
193 public subscript(index: Index) -> UInt8 {
194 var offset = 0
195 let subdata = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, index, &offset)
196
197 var ptr: UnsafeRawPointer? = nil
198 var size = 0
199 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
200 defer { _fixLifetime(map) }
201
202 return ptr!.load(fromByteOffset: index - offset, as: UInt8.self)
203 }
204
205 public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
206 return RandomAccessSlice(base: self, bounds: bounds)
207 }
208
209 /// Return a new copy of the data in a specified range.
210 ///
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)
216 }
217
218 public func region(location: Int) -> (data: DispatchData, offset: Int) {
219 var offset: Int = 0
220 let data = CDispatch.dispatch_data_copy_region(__wrapped.__wrapped, location, &offset)
221 return (DispatchData(data: data), offset)
222 }
223
224 public var startIndex: Index {
225 return 0
226 }
227
228 public var endIndex: Index {
229 return count
230 }
231
232 public func index(before i: Index) -> Index {
233 return i - 1
234 }
235
236 public func index(after i: Index) -> Index {
237 return i + 1
238 }
239
240 /// An iterator over the contents of the data.
241 ///
242 /// The iterator will increment byte-by-byte.
243 public func makeIterator() -> DispatchData.Iterator {
244 return DispatchDataIterator(_data: self)
245 }
246 }
247
248 public struct DispatchDataIterator : IteratorProtocol, Sequence {
249
250 /// Create an iterator over the given DispatchData
251 public init(_data: DispatchData) {
252 var ptr: UnsafeRawPointer?
253 self._count = 0
254 self._data = __DispatchData(data: CDispatch.dispatch_data_create_map(_data.__wrapped.__wrapped, &ptr, &self._count), owned: true)
255 self._ptr = ptr
256 self._position = _data.startIndex
257
258 // The only time we expect a 'nil' pointer is when the data is empty.
259 assert(self._ptr != nil || self._count == self._position)
260 }
261
262 /// Advance to the next element and return it, or `nil` if no next
263 /// element exists.
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
268 return element
269 }
270
271 internal let _data: __DispatchData
272 internal var _ptr: UnsafeRawPointer!
273 internal var _count: Int
274 internal var _position: DispatchData.Index
275 }
276
277 typealias _swift_data_applier = @convention(block) (dispatch_data_t, Int, UnsafeRawPointer, Int) -> Bool
278
279 @_silgen_name("_swift_dispatch_data_apply")
280 internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier)
281
282 @_silgen_name("_swift_dispatch_data_empty")
283 internal func _swift_dispatch_data_empty() -> dispatch_data_t
284
285 @_silgen_name("_swift_dispatch_data_destructor_free")
286 internal func _dispatch_data_destructor_free() -> _DispatchBlock
287
288 @_silgen_name("_swift_dispatch_data_destructor_munmap")
289 internal func _dispatch_data_destructor_munmap() -> _DispatchBlock
290
291 @_silgen_name("_swift_dispatch_data_destructor_default")
292 internal func _dispatch_data_destructor_default() -> _DispatchBlock