Skip to content

Commit 9770256

Browse files
Merge pull request #571 from michael-lehew/master
Swift 3 Darwin Parity (many types)
2 parents 12f9dd2 + d452b0e commit 9770256

23 files changed

+1331
-604
lines changed

Foundation/Data.swift

Lines changed: 112 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -73,56 +73,15 @@ internal final class _SwiftNSData : NSData, _SwiftNativeFoundationType {
7373
releaseWrappedObject()
7474
}
7575

76-
// Stubs
77-
// -----
78-
76+
// MARK: - Funnel overrides
7977
override var length : Int {
8078
get {
8179
return _mapUnmanaged { $0.length }
8280
}
8381
}
84-
8582
override var bytes : UnsafeRawPointer {
8683
return _mapUnmanaged { $0.bytes }
8784
}
88-
89-
// override func subdata(with range: NSRange) -> Data {
90-
// return _mapUnmanaged { $0.subdata(with: range) }
91-
// }
92-
//
93-
// override func getBytes(_ buffer: UnsafeMutableRawPointer, length: Int) {
94-
// return _mapUnmanaged { $0.getBytes(buffer, length: length) }
95-
// }
96-
//
97-
// override func getBytes(_ buffer: UnsafeMutableRawPointer, range: NSRange) {
98-
// return _mapUnmanaged { $0.getBytes(buffer, range: range) }
99-
// }
100-
//
101-
// override func isEqual(to other: Data) -> Bool {
102-
// return _mapUnmanaged { return $0.isEqual(to: other) }
103-
// }
104-
//
105-
// override func write(to url: URL, options: Data.WritingOptions) throws {
106-
// return try _mapUnmanaged { try $0.write(to: url, options: options) }
107-
// }
108-
//
109-
// override func range(of data: Data, options: Data.SearchOptions, range: NSRange) -> NSRange {
110-
// return _mapUnmanaged {
111-
// $0.range(of: data, options: options, in: range)
112-
// }
113-
// }
114-
//
115-
// override func enumerateByteRanges(using block: (UnsafeRawPointer, NSRange, UnsafeMutablePointer<ObjCBool>) -> Void) {
116-
// return _mapUnmanaged { $0.enumerateBytes(block) }
117-
// }
118-
//
119-
// override func base64EncodedString(options: Data.Base64EncodingOptions) -> String {
120-
// return _mapUnmanaged { $0.base64EncodedString(options) }
121-
// }
122-
//
123-
// override func base64EncodedData(options: Data.Base64EncodingOptions) -> Data {
124-
// return _mapUnmanaged { $0.base64EncodedData(options) }
125-
// }
12685
}
12786

12887
/**
@@ -197,10 +156,17 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
197156
_wrapped = _SwiftNSData(immutableObject: NSData(bytes: buffer.baseAddress, length: MemoryLayout<SourceType>.stride * buffer.count))
198157
}
199158

159+
/// Initialize a `Data` with copied memory content.
160+
///
161+
/// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
162+
public init<SourceType>(buffer: UnsafeMutableBufferPointer<SourceType>) {
163+
_wrapped = _SwiftNSData(immutableObject: NSData(bytes: UnsafePointer(buffer.baseAddress), length: MemoryLayout<SourceType>.stride * buffer.count))
164+
}
165+
200166
/// Initialize a `Data` with the contents of an Array.
201167
///
202168
/// - parameter bytes: An array of bytes to copy.
203-
public init(bytes: Array<UInt8>) {
169+
public init(bytes: [UInt8]) {
204170
_wrapped = bytes.withUnsafeBufferPointer {
205171
return _SwiftNSData(immutableObject: NSData(bytes: $0.baseAddress, length: $0.count))
206172
}
@@ -226,7 +192,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
226192
/// - parameter capacity: The size of the data.
227193
public init(capacity: Int) {
228194
if let d = NSMutableData(capacity: capacity) {
229-
_wrapped = _SwiftNSData(immutableObject: d)
195+
_wrapped = _SwiftNSData(mutableObject: d)
230196
} else {
231197
fatalError("Unable to allocate data of the requested capacity")
232198
}
@@ -261,7 +227,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
261227
///
262228
/// Returns nil when the input is not recognized as valid Base-64.
263229
/// - parameter base64String: The string to parse.
264-
/// - parameter options: Decoding options. Default value is `[]`.
230+
/// - parameter options: Encoding options. Default value is `[]`.
265231
public init?(base64Encoded base64String: String, options: Data.Base64DecodingOptions = []) {
266232
if let d = NSData(base64Encoded: base64String, options: Base64DecodingOptions(rawValue: options.rawValue)) {
267233
_wrapped = _SwiftNSData(immutableObject: d)
@@ -288,16 +254,24 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
288254
///
289255
/// - parameter count: The number of bytes the data initially contains.
290256
public init(count: Int) {
291-
if let memory = calloc(1, count)?.bindMemory(to: UInt8.self, capacity: count) {
292-
self.init(bytesNoCopy: memory, count: count, deallocator: .free)
257+
if let d = NSMutableData(length: count) {
258+
_wrapped = _SwiftNSData(mutableObject: d)
293259
} else {
294260
fatalError("Unable to allocate data of the requested count")
295261
}
296262
}
263+
297264

298-
internal init(_bridged data: NSData) {
299-
// We must copy the input because it might be mutable; just like storing a value type in ObjC
300-
_wrapped = _SwiftNSData(immutableObject: data.copy() as! NSObject)
265+
/// Initialize a `Data` by adopting a reference type.
266+
///
267+
/// You can use this initializer to create a `struct Data` that wraps a `class NSData`. `struct Data` will use the `class NSData` for all operations. Other initializers (including casting using `as Data`) may choose to hold a reference or not, based on a what is the most efficient representation.
268+
///
269+
/// If the resulting value is mutated, then `Data` will invoke the `mutableCopy()` function on the reference to copy the contents. You may customize the behavior of that function if you wish to return a specialized mutable subclass.
270+
///
271+
/// - parameter reference: The instance of `NSData` that you wish to wrap. This instance will be copied by `struct Data`.
272+
public init(referencing reference: NSData) {
273+
// NOTE: don't fix this warning on Darwin -- linux will complain
274+
_wrapped = _SwiftNSData(immutableObject: reference.copy() as! AnyObject)
301275
}
302276

303277
// -----------------------------------
@@ -356,7 +330,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
356330
_mapUnmanaged { $0.getBytes(pointer, length: count) }
357331
}
358332

359-
private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: NSRange) {
333+
private func _copyBytesHelper(to pointer: UnsafeMutablePointer<UInt8>, from range: NSRange) {
360334
_mapUnmanaged { $0.getBytes(pointer, range: range) }
361335
}
362336

@@ -366,7 +340,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
366340
/// - parameter range: The range in the `Data` to copy.
367341
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
368342
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, from range: Range<Index>) {
369-
_copyBytesHelper(to: pointer, from: NSRange(location: range.lowerBound, length: range.upperBound - range.lowerBound))
343+
_copyBytesHelper(to: pointer, from: NSRange(range))
370344
}
371345

372346
/// Copy the contents of the data into a buffer.
@@ -397,8 +371,10 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
397371
guard !copyRange.isEmpty else { return 0 }
398372

399373
let nsRange = NSMakeRange(copyRange.lowerBound, copyRange.upperBound - copyRange.lowerBound)
400-
let pointer = UnsafeMutableRawPointer(buffer.baseAddress!)
401-
_copyBytesHelper(to: pointer, from: nsRange)
374+
let ptr = buffer.baseAddress!
375+
ptr.withMemoryRebound(to: UInt8.self, capacity: buffer.count) {
376+
_copyBytesHelper(to: $0, from: nsRange)
377+
}
402378
return copyRange.count
403379
}
404380

@@ -499,10 +475,13 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
499475

500476
/// Replace a region of bytes in the data with new data.
501477
///
502-
/// - parameter range: The range in the data to replace.
478+
/// This will resize the data if required, to fit the entire contents of `data`.
479+
///
480+
/// - precondition: The bounds of `subrange` must be valid indices of the collection.
481+
/// - parameter subrange: The range in the data to replace. If `subrange.lowerBound == data.count && subrange.count == 0` then this operation is an append.
503482
/// - parameter data: The replacement data.
504-
public mutating func replaceBytes(in range: Range<Index>, with data: Data) {
505-
let nsRange = NSMakeRange(range.lowerBound, range.upperBound - range.lowerBound)
483+
public mutating func replaceSubrange(_ subrange: Range<Index>, with data: Data) {
484+
let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
506485
let cnt = data.count
507486
let bytes = data._getUnsafeBytesPointer()
508487

@@ -511,6 +490,68 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
511490
}
512491
}
513492

493+
/// Replace a region of bytes in the data with new bytes from a buffer.
494+
///
495+
/// This will resize the data if required, to fit the entire contents of `buffer`.
496+
///
497+
/// - precondition: The bounds of `subrange` must be valid indices of the collection.
498+
/// - parameter subrange: The range in the data to replace.
499+
/// - parameter buffer: The replacement bytes.
500+
public mutating func replaceSubrange<SourceType>(_ subrange: Range<Index>, with buffer: UnsafeBufferPointer<SourceType>) {
501+
let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
502+
let bufferCount = buffer.count * MemoryLayout<SourceType>.stride
503+
504+
_applyUnmanagedMutation {
505+
$0.replaceBytes(in: nsRange, withBytes: buffer.baseAddress!, length: bufferCount)
506+
}
507+
508+
}
509+
510+
/// Replace a region of bytes in the data with new bytes from a collection.
511+
///
512+
/// This will resize the data if required, to fit the entire contents of `newElements`.
513+
///
514+
/// - precondition: The bounds of `subrange` must be valid indices of the collection.
515+
/// - parameter subrange: The range in the data to replace.
516+
/// - parameter newElements: The replacement bytes.
517+
public mutating func replaceSubrange<ByteCollection : Collection>(_ subrange: Range<Index>, with newElements: ByteCollection) where ByteCollection.Iterator.Element == Data.Iterator.Element {
518+
519+
// Calculate this once, it may not be O(1)
520+
let replacementCount : Int = numericCast(newElements.count)
521+
let currentCount = self.count
522+
let subrangeCount = subrange.count
523+
524+
if currentCount < subrange.lowerBound + subrangeCount {
525+
if subrangeCount == 0 {
526+
preconditionFailure("location \(subrange.lowerBound) exceeds data count \(currentCount)")
527+
} else {
528+
preconditionFailure("range \(subrange) exceeds data count \(currentCount)")
529+
}
530+
}
531+
532+
let resultCount = currentCount - subrangeCount + replacementCount
533+
if resultCount != currentCount {
534+
// This may realloc.
535+
// In the future, if we keep the malloced pointer and count inside this struct/ref instead of deferring to NSData, we may be able to do this more efficiently.
536+
self.count = resultCount
537+
}
538+
539+
let shift = resultCount - currentCount
540+
let start = subrange.lowerBound
541+
542+
self.withUnsafeMutableBytes { (bytes : UnsafeMutablePointer<UInt8>) -> () in
543+
if shift != 0 {
544+
let destination = bytes + start + replacementCount
545+
let source = bytes + start + subrangeCount
546+
memmove(destination, source, currentCount - start - subrangeCount)
547+
}
548+
549+
if replacementCount != 0 {
550+
newElements._copyContents(initializing: bytes + start)
551+
}
552+
}
553+
}
554+
514555
/// Return a new copy of the data in a specified range.
515556
///
516557
/// - parameter range: The range to copy.
@@ -526,16 +567,16 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
526567
///
527568
/// - parameter options: The options to use for the encoding. Default value is `[]`.
528569
/// - returns: The Base-64 encoded string.
529-
public func base64EncodedString(_ options: Data.Base64EncodingOptions = []) -> String {
530-
return _mapUnmanaged { $0.base64EncodedString(options) }
570+
public func base64EncodedString(options: Data.Base64EncodingOptions = []) -> String {
571+
return _mapUnmanaged { $0.base64EncodedString(options: options) }
531572
}
532573

533574
/// Returns a Base-64 encoded `Data`.
534575
///
535576
/// - parameter options: The options to use for the encoding. Default value is `[]`.
536577
/// - returns: The Base-64 encoded data.
537-
public func base64EncodedData(_ options: Data.Base64EncodingOptions = []) -> Data {
538-
return _mapUnmanaged { $0.base64EncodedData(options) }
578+
public func base64EncodedData(options: Data.Base64EncodingOptions = []) -> Data {
579+
return _mapUnmanaged { $0.base64EncodedData(options: options) }
539580
}
540581

541582
// MARK: -
@@ -556,7 +597,6 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
556597
return _mapUnmanaged { $0.debugDescription }
557598
}
558599

559-
// MARK: -
560600

561601
// MARK: -
562602
// MARK: Index and Subscript
@@ -577,20 +617,12 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
577617
}
578618
}
579619

580-
public subscript(bounds: Range<Int>) -> MutableRandomAccessSlice<Data> {
620+
public subscript(bounds: Range<Index>) -> MutableRandomAccessSlice<Data> {
581621
get {
582622
return MutableRandomAccessSlice(base: self, bounds: bounds)
583623
}
584624
set {
585-
// Ideally this would be:
586-
// replaceBytes(in: bounds, with: newValue._base)
587-
// but we do not have access to _base due to 'internal' protection
588-
// TODO: Use a custom Slice type so we have access to the underlying data
589-
let arrayOfBytes = newValue.map { $0 }
590-
arrayOfBytes.withUnsafeBufferPointer {
591-
let otherData = Data(buffer: $0)
592-
replaceBytes(in: bounds, with: otherData)
593-
}
625+
replaceSubrange(bounds, with: newValue.base)
594626
}
595627
}
596628

@@ -620,12 +652,14 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
620652
public func makeIterator() -> Data.Iterator {
621653
return IndexingIterator(_elements: self)
622654
}
655+
656+
/// Returns `true` if the two `Data` arguments are equal.
657+
public static func ==(d1 : Data, d2 : Data) -> Bool {
658+
return d1._wrapped.isEqual(to: d2)
659+
}
623660
}
624661

625-
/// Returns `true` if the two `Data` arguments are equal.
626-
public func ==(d1 : Data, d2 : Data) -> Bool {
627-
return d1._wrapped.isEqual(to: d2)
628-
}
662+
629663

630664
/// Provides bridging functionality for struct Data to class NSData and vice-versa.
631665
extension Data : _ObjectTypeBridgeable {
@@ -639,11 +673,11 @@ extension Data : _ObjectTypeBridgeable {
639673
}
640674

641675
public static func _forceBridgeFromObjectiveC(_ input: NSData, result: inout Data?) {
642-
result = Data(_bridged: input)
676+
result = Data(referencing: input)
643677
}
644678

645679
public static func _conditionallyBridgeFromObjectiveC(_ input: NSData, result: inout Data?) -> Bool {
646-
result = Data(_bridged: input)
680+
result = Data(referencing: input)
647681
return true
648682
}
649683

Foundation/NSConcreteValue.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,8 @@ internal class NSConcreteValue : NSValue {
113113
}
114114

115115
override var description : String {
116-
return Data(bytes: self.value, count: self._size).description
116+
let boundBytes = self.value.bindMemory(to: UInt8.self, capacity: self._size)
117+
return Data(bytes: boundBytes, count: self._size).description
117118
}
118119

119120
convenience required init?(coder aDecoder: NSCoder) {

0 commit comments

Comments
 (0)