@@ -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,23 @@ 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+ _wrapped = _SwiftNSData ( immutableObject: reference. copy ( ) as! AnyObject )
301274 }
302275
303276 // -----------------------------------
@@ -356,7 +329,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
356329 _mapUnmanaged { $0. getBytes ( pointer, length: count) }
357330 }
358331
359- private func _copyBytesHelper( to pointer: UnsafeMutableRawPointer , from range: NSRange ) {
332+ private func _copyBytesHelper( to pointer: UnsafeMutablePointer < UInt8 > , from range: NSRange ) {
360333 _mapUnmanaged { $0. getBytes ( pointer, range: range) }
361334 }
362335
@@ -366,7 +339,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
366339 /// - parameter range: The range in the `Data` to copy.
367340 /// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
368341 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 ) )
342+ _copyBytesHelper ( to: pointer, from: NSRange ( range) )
370343 }
371344
372345 /// Copy the contents of the data into a buffer.
@@ -397,8 +370,10 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
397370 guard !copyRange. isEmpty else { return 0 }
398371
399372 let nsRange = NSMakeRange ( copyRange. lowerBound, copyRange. upperBound - copyRange. lowerBound)
400- let pointer = UnsafeMutableRawPointer ( buffer. baseAddress!)
401- _copyBytesHelper ( to: pointer, from: nsRange)
373+ let ptr = buffer. baseAddress!
374+ ptr. withMemoryRebound ( to: UInt8 . self, capacity: buffer. count) {
375+ _copyBytesHelper ( to: $0, from: nsRange)
376+ }
402377 return copyRange. count
403378 }
404379
@@ -499,10 +474,13 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
499474
500475 /// Replace a region of bytes in the data with new data.
501476 ///
502- /// - parameter range: The range in the data to replace.
477+ /// This will resize the data if required, to fit the entire contents of `data`.
478+ ///
479+ /// - precondition: The bounds of `subrange` must be valid indices of the collection.
480+ /// - parameter subrange: The range in the data to replace. If `subrange.lowerBound == data.count && subrange.count == 0` then this operation is an append.
503481 /// - 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)
482+ public mutating func replaceSubrange ( _ subrange : Range < Index > , with data: Data ) {
483+ let nsRange = NSMakeRange ( subrange . lowerBound, subrange . upperBound - subrange . lowerBound)
506484 let cnt = data. count
507485 let bytes = data. _getUnsafeBytesPointer ( )
508486
@@ -511,6 +489,68 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
511489 }
512490 }
513491
492+ /// Replace a region of bytes in the data with new bytes from a buffer.
493+ ///
494+ /// This will resize the data if required, to fit the entire contents of `buffer`.
495+ ///
496+ /// - precondition: The bounds of `subrange` must be valid indices of the collection.
497+ /// - parameter subrange: The range in the data to replace.
498+ /// - parameter buffer: The replacement bytes.
499+ public mutating func replaceSubrange< SourceType> ( _ subrange: Range < Index > , with buffer: UnsafeBufferPointer < SourceType > ) {
500+ let nsRange = NSMakeRange ( subrange. lowerBound, subrange. upperBound - subrange. lowerBound)
501+ let bufferCount = buffer. count * MemoryLayout< SourceType> . stride
502+
503+ _applyUnmanagedMutation {
504+ $0. replaceBytes ( in: nsRange, withBytes: buffer. baseAddress!, length: bufferCount)
505+ }
506+
507+ }
508+
509+ /// Replace a region of bytes in the data with new bytes from a collection.
510+ ///
511+ /// This will resize the data if required, to fit the entire contents of `newElements`.
512+ ///
513+ /// - precondition: The bounds of `subrange` must be valid indices of the collection.
514+ /// - parameter subrange: The range in the data to replace.
515+ /// - parameter newElements: The replacement bytes.
516+ public mutating func replaceSubrange< ByteCollection : Collection > ( _ subrange: Range < Index > , with newElements: ByteCollection ) where ByteCollection. Iterator. Element == Data . Iterator . Element {
517+
518+ // Calculate this once, it may not be O(1)
519+ let replacementCount : Int = numericCast ( newElements. count)
520+ let currentCount = self . count
521+ let subrangeCount = subrange. count
522+
523+ if currentCount < subrange. lowerBound + subrangeCount {
524+ if subrangeCount == 0 {
525+ preconditionFailure ( " location \( subrange. lowerBound) exceeds data count \( currentCount) " )
526+ } else {
527+ preconditionFailure ( " range \( subrange) exceeds data count \( currentCount) " )
528+ }
529+ }
530+
531+ let resultCount = currentCount - subrangeCount + replacementCount
532+ if resultCount != currentCount {
533+ // This may realloc.
534+ // 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.
535+ self . count = resultCount
536+ }
537+
538+ let shift = resultCount - currentCount
539+ let start = subrange. lowerBound
540+
541+ self . withUnsafeMutableBytes { ( bytes : UnsafeMutablePointer < UInt8 > ) -> ( ) in
542+ if shift != 0 {
543+ let destination = bytes + start + replacementCount
544+ let source = bytes + start + subrangeCount
545+ memmove ( destination, source, currentCount - start - subrangeCount)
546+ }
547+
548+ if replacementCount != 0 {
549+ newElements. _copyContents ( initializing: bytes + start)
550+ }
551+ }
552+ }
553+
514554 /// Return a new copy of the data in a specified range.
515555 ///
516556 /// - parameter range: The range to copy.
@@ -526,16 +566,16 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
526566 ///
527567 /// - parameter options: The options to use for the encoding. Default value is `[]`.
528568 /// - returns: The Base-64 encoded string.
529- public func base64EncodedString( _ options: Data . Base64EncodingOptions = [ ] ) -> String {
530- return _mapUnmanaged { $0. base64EncodedString ( options) }
569+ public func base64EncodedString( options: Data . Base64EncodingOptions = [ ] ) -> String {
570+ return _mapUnmanaged { $0. base64EncodedString ( options: options ) }
531571 }
532572
533573 /// Returns a Base-64 encoded `Data`.
534574 ///
535575 /// - parameter options: The options to use for the encoding. Default value is `[]`.
536576 /// - returns: The Base-64 encoded data.
537- public func base64EncodedData( _ options: Data . Base64EncodingOptions = [ ] ) -> Data {
538- return _mapUnmanaged { $0. base64EncodedData ( options) }
577+ public func base64EncodedData( options: Data . Base64EncodingOptions = [ ] ) -> Data {
578+ return _mapUnmanaged { $0. base64EncodedData ( options: options ) }
539579 }
540580
541581 // MARK: -
@@ -556,7 +596,6 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
556596 return _mapUnmanaged { $0. debugDescription }
557597 }
558598
559- // MARK: -
560599
561600 // MARK: -
562601 // MARK: Index and Subscript
@@ -577,20 +616,12 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
577616 }
578617 }
579618
580- public subscript( bounds: Range < Int > ) -> MutableRandomAccessSlice < Data > {
619+ public subscript( bounds: Range < Index > ) -> MutableRandomAccessSlice < Data > {
581620 get {
582621 return MutableRandomAccessSlice ( base: self , bounds: bounds)
583622 }
584623 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- }
624+ replaceSubrange ( bounds, with: newValue. base)
594625 }
595626 }
596627
@@ -620,12 +651,14 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
620651 public func makeIterator( ) -> Data . Iterator {
621652 return IndexingIterator ( _elements: self )
622653 }
654+
655+ /// Returns `true` if the two `Data` arguments are equal.
656+ public static func == ( d1 : Data , d2 : Data ) -> Bool {
657+ return d1. _wrapped. isEqual ( to: d2)
658+ }
623659}
624660
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- }
661+
629662
630663/// Provides bridging functionality for struct Data to class NSData and vice-versa.
631664extension Data : _ObjectTypeBridgeable {
@@ -639,11 +672,11 @@ extension Data : _ObjectTypeBridgeable {
639672 }
640673
641674 public static func _forceBridgeFromObjectiveC( _ input: NSData , result: inout Data ? ) {
642- result = Data ( _bridged : input)
675+ result = Data ( referencing : input)
643676 }
644677
645678 public static func _conditionallyBridgeFromObjectiveC( _ input: NSData , result: inout Data ? ) -> Bool {
646- result = Data ( _bridged : input)
679+ result = Data ( referencing : input)
647680 return true
648681 }
649682
0 commit comments