]> git.saurik.com Git - apple/libdispatch.git/blob - src/swift/Data.swift
libdispatch-703.30.5.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 #if false /* FIXME: dragging in _TMBO (Objective-C) */
23 public enum Deallocator {
24 /// Use `free`
25 case free
26
27 /// Use `munmap`
28 case unmap
29
30 /// A custom deallocator
31 case custom(DispatchQueue?, @convention(block) () -> Void)
32
33 private var _deallocator: (DispatchQueue?, @convention(block) () -> Void) {
34 switch self {
35 case .free: return (nil, _dispatch_data_destructor_free())
36 case .unmap: return (nil, _dispatch_data_destructor_munmap())
37 case .custom(let q, let b): return (q, b)
38 }
39 }
40 }
41 #endif
42 internal var __wrapped: dispatch_data_t
43
44 /// Initialize a `Data` with copied memory content.
45 ///
46 /// - parameter bytes: A pointer to the memory. It will be copied.
47 /// - parameter count: The number of bytes to copy.
48 public init(bytes buffer: UnsafeBufferPointer<UInt8>) {
49 __wrapped = dispatch_data_create(
50 buffer.baseAddress!, buffer.count, nil, _dispatch_data_destructor_default())
51 }
52 #if false /* FIXME: dragging in _TMBO (Objective-C) */
53 /// Initialize a `Data` without copying the bytes.
54 ///
55 /// - parameter bytes: A pointer to the bytes.
56 /// - parameter count: The size of the bytes.
57 /// - parameter deallocator: Specifies the mechanism to free the indicated buffer.
58 public init(bytesNoCopy bytes: UnsafeBufferPointer<UInt8>, deallocator: Deallocator = .free) {
59 let (q, b) = deallocator._deallocator
60
61 __wrapped = dispatch_data_create(bytes.baseAddress!, bytes.count, q?.__wrapped, b)
62 }
63 #endif
64 internal init(data: dispatch_data_t) {
65 __wrapped = data
66 }
67
68 public var count: Int {
69 return CDispatch.dispatch_data_get_size(__wrapped)
70 }
71
72 public func withUnsafeBytes<Result, ContentType>(
73 body: @noescape (UnsafePointer<ContentType>) throws -> Result) rethrows -> Result
74 {
75 var ptr: UnsafePointer<Void>? = nil
76 var size = 0;
77 let data = CDispatch.dispatch_data_create_map(__wrapped, &ptr, &size)
78 defer { _fixLifetime(data) }
79 return try body(UnsafePointer<ContentType>(ptr!))
80 }
81
82 public func enumerateBytes(
83 block: @noescape (buffer: UnsafeBufferPointer<UInt8>, byteIndex: Int, stop: inout Bool) -> Void)
84 {
85 _swift_dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
86 let bp = UnsafeBufferPointer(start: UnsafePointer<UInt8>(ptr), count: size)
87 var stop = false
88 block(buffer: bp, byteIndex: offset, stop: &stop)
89 return !stop
90 }
91 }
92
93 /// Append bytes to the data.
94 ///
95 /// - parameter bytes: A pointer to the bytes to copy in to the data.
96 /// - parameter count: The number of bytes to copy.
97 public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
98 let data = dispatch_data_create(bytes, count, nil, _dispatch_data_destructor_default())
99 self.append(DispatchData(data: data))
100 }
101
102 /// Append data to the data.
103 ///
104 /// - parameter data: The data to append to this data.
105 public mutating func append(_ other: DispatchData) {
106 let data = CDispatch.dispatch_data_create_concat(__wrapped, other.__wrapped)
107 __wrapped = data
108 }
109
110 /// Append a buffer of bytes to the data.
111 ///
112 /// - parameter buffer: The buffer of bytes to append. The size is calculated from `SourceType` and `buffer.count`.
113 public mutating func append<SourceType>(_ buffer : UnsafeBufferPointer<SourceType>) {
114 self.append(UnsafePointer(buffer.baseAddress!), count: buffer.count * sizeof(SourceType.self))
115 }
116
117 private func _copyBytesHelper(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
118 var copiedCount = 0
119 _ = CDispatch.dispatch_data_apply(__wrapped) { (data: dispatch_data_t, offset: Int, ptr: UnsafePointer<Void>, size: Int) in
120 let limit = Swift.min((range.endIndex - range.startIndex) - copiedCount, size)
121 memcpy(pointer + copiedCount, ptr, limit)
122 copiedCount += limit
123 return copiedCount < (range.endIndex - range.startIndex)
124 }
125 }
126
127 /// Copy the contents of the data to a pointer.
128 ///
129 /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
130 /// - parameter count: The number of bytes to copy.
131 /// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
132 public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
133 _copyBytesHelper(to: pointer, from: 0..<count)
134 }
135
136 /// Copy a subset of the contents of the data to a pointer.
137 ///
138 /// - parameter pointer: A pointer to the buffer you wish to copy the bytes into.
139 /// - parameter range: The range in the `Data` to copy.
140 /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
141 public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: CountableRange<Index>) {
142 _copyBytesHelper(to: pointer, from: range)
143 }
144
145 /// Copy the contents of the data into a buffer.
146 ///
147 /// This function copies the bytes in `range` from the data into the buffer. If the count of the `range` is greater than `sizeof(DestinationType) * buffer.count` then the first N bytes will be copied into the buffer.
148 /// - precondition: The range must be within the bounds of the data. Otherwise `fatalError` is called.
149 /// - parameter buffer: A buffer to copy the data into.
150 /// - 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.
151 /// - returns: Number of bytes copied into the destination buffer.
152 public func copyBytes<DestinationType>(to buffer: UnsafeMutableBufferPointer<DestinationType>, from range: CountableRange<Index>? = nil) -> Int {
153 let cnt = count
154 guard cnt > 0 else { return 0 }
155
156 let copyRange : CountableRange<Index>
157 if let r = range {
158 guard !r.isEmpty else { return 0 }
159 precondition(r.startIndex >= 0)
160 precondition(r.startIndex < cnt, "The range is outside the bounds of the data")
161
162 precondition(r.endIndex >= 0)
163 precondition(r.endIndex <= cnt, "The range is outside the bounds of the data")
164
165 copyRange = r.startIndex..<(r.startIndex + Swift.min(buffer.count * sizeof(DestinationType.self), r.count))
166 } else {
167 copyRange = 0..<Swift.min(buffer.count * sizeof(DestinationType.self), cnt)
168 }
169
170 guard !copyRange.isEmpty else { return 0 }
171
172 let pointer : UnsafeMutablePointer<UInt8> = UnsafeMutablePointer<UInt8>(buffer.baseAddress!)
173 _copyBytesHelper(to: pointer, from: copyRange)
174 return copyRange.count
175 }
176
177 /// Sets or returns the byte at the specified index.
178 public subscript(index: Index) -> UInt8 {
179 var offset = 0
180 let subdata = CDispatch.dispatch_data_copy_region(__wrapped, index, &offset)
181
182 var ptr: UnsafePointer<Void>? = nil
183 var size = 0
184 let map = CDispatch.dispatch_data_create_map(subdata, &ptr, &size)
185 defer { _fixLifetime(map) }
186
187 let pptr = UnsafePointer<UInt8>(ptr!)
188 return pptr[index - offset]
189 }
190
191 public subscript(bounds: Range<Int>) -> RandomAccessSlice<DispatchData> {
192 return RandomAccessSlice(base: self, bounds: bounds)
193 }
194
195 /// Return a new copy of the data in a specified range.
196 ///
197 /// - parameter range: The range to copy.
198 public func subdata(in range: CountableRange<Index>) -> DispatchData {
199 let subrange = CDispatch.dispatch_data_create_subrange(
200 __wrapped, range.startIndex, range.endIndex - range.startIndex)
201 return DispatchData(data: subrange)
202 }
203
204 public func region(location: Int) -> (data: DispatchData, offset: Int) {
205 var offset: Int = 0
206 let data = CDispatch.dispatch_data_copy_region(__wrapped, location, &offset)
207 return (DispatchData(data: data), offset)
208 }
209
210 public var startIndex: Index {
211 return 0
212 }
213
214 public var endIndex: Index {
215 return count
216 }
217
218 public func index(before i: Index) -> Index {
219 return i - 1
220 }
221
222 public func index(after i: Index) -> Index {
223 return i + 1
224 }
225
226 /// An iterator over the contents of the data.
227 ///
228 /// The iterator will increment byte-by-byte.
229 public func makeIterator() -> DispatchData.Iterator {
230 return DispatchDataIterator(_data: self)
231 }
232 }
233
234 public struct DispatchDataIterator : IteratorProtocol, Sequence {
235
236 /// Create an iterator over the given DisaptchData
237 public init(_data: DispatchData) {
238 var ptr: UnsafePointer<Void>?
239 self._count = 0
240 self._data = CDispatch.dispatch_data_create_map(_data.__wrapped, &ptr, &self._count)
241 self._ptr = UnsafePointer(ptr!)
242 self._position = _data.startIndex
243 }
244
245 /// Advance to the next element and return it, or `nil` if no next
246 /// element exists.
247 ///
248 /// - Precondition: No preceding call to `self.next()` has returned `nil`.
249 public mutating func next() -> DispatchData._Element? {
250 if _position == _count { return nil }
251 let element = _ptr[_position];
252 _position = _position + 1
253 return element
254 }
255
256 internal let _data: dispatch_data_t
257 internal var _ptr: UnsafePointer<UInt8>
258 internal var _count: Int
259 internal var _position: DispatchData.Index
260 }
261
262 typealias _swift_data_applier = @convention(block) @noescape (dispatch_data_t, Int, UnsafePointer<Void>, Int) -> Bool
263
264 @_silgen_name("_swift_dispatch_data_apply")
265 internal func _swift_dispatch_data_apply(_ data: dispatch_data_t, _ block: _swift_data_applier)
266
267 @_silgen_name("_swift_dispatch_data_empty")
268 internal func _swift_dispatch_data_empty() -> dispatch_data_t
269
270 @_silgen_name("_swift_dispatch_data_destructor_free")
271 internal func _dispatch_data_destructor_free() -> _DispatchBlock
272
273 @_silgen_name("_swift_dispatch_data_destructor_munmap")
274 internal func _dispatch_data_destructor_munmap() -> _DispatchBlock
275
276 @_silgen_name("_swift_dispatch_data_destructor_default")
277 internal func _dispatch_data_destructor_default() -> _DispatchBlock