@@ -73,56 +73,15 @@ internal final class _SwiftNSData : NSData, _SwiftNativeFoundationType {
73
73
releaseWrappedObject ( )
74
74
}
75
75
76
- // Stubs
77
- // -----
78
-
76
+ // MARK: - Funnel overrides
79
77
override var length : Int {
80
78
get {
81
79
return _mapUnmanaged { $0. length }
82
80
}
83
81
}
84
-
85
82
override var bytes : UnsafeRawPointer {
86
83
return _mapUnmanaged { $0. bytes }
87
84
}
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
- // }
126
85
}
127
86
128
87
/**
@@ -197,10 +156,17 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
197
156
_wrapped = _SwiftNSData ( immutableObject: NSData ( bytes: buffer. baseAddress, length: MemoryLayout < SourceType > . stride * buffer. count) )
198
157
}
199
158
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
+
200
166
/// Initialize a `Data` with the contents of an Array.
201
167
///
202
168
/// - parameter bytes: An array of bytes to copy.
203
- public init ( bytes: Array < UInt8 > ) {
169
+ public init ( bytes: [ UInt8 ] ) {
204
170
_wrapped = bytes. withUnsafeBufferPointer {
205
171
return _SwiftNSData ( immutableObject: NSData ( bytes: $0. baseAddress, length: $0. count) )
206
172
}
@@ -226,7 +192,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
226
192
/// - parameter capacity: The size of the data.
227
193
public init ( capacity: Int ) {
228
194
if let d = NSMutableData ( capacity: capacity) {
229
- _wrapped = _SwiftNSData ( immutableObject : d)
195
+ _wrapped = _SwiftNSData ( mutableObject : d)
230
196
} else {
231
197
fatalError ( " Unable to allocate data of the requested capacity " )
232
198
}
@@ -261,7 +227,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
261
227
///
262
228
/// Returns nil when the input is not recognized as valid Base-64.
263
229
/// - parameter base64String: The string to parse.
264
- /// - parameter options: Decoding options. Default value is `[]`.
230
+ /// - parameter options: Encoding options. Default value is `[]`.
265
231
public init ? ( base64Encoded base64String: String , options: Data . Base64DecodingOptions = [ ] ) {
266
232
if let d = NSData ( base64Encoded: base64String, options: Base64DecodingOptions ( rawValue: options. rawValue) ) {
267
233
_wrapped = _SwiftNSData ( immutableObject: d)
@@ -288,16 +254,24 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
288
254
///
289
255
/// - parameter count: The number of bytes the data initially contains.
290
256
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 )
293
259
} else {
294
260
fatalError ( " Unable to allocate data of the requested count " )
295
261
}
296
262
}
263
+
297
264
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 )
301
275
}
302
276
303
277
// -----------------------------------
@@ -356,7 +330,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
356
330
_mapUnmanaged { $0. getBytes ( pointer, length: count) }
357
331
}
358
332
359
- private func _copyBytesHelper( to pointer: UnsafeMutableRawPointer , from range: NSRange ) {
333
+ private func _copyBytesHelper( to pointer: UnsafeMutablePointer < UInt8 > , from range: NSRange ) {
360
334
_mapUnmanaged { $0. getBytes ( pointer, range: range) }
361
335
}
362
336
@@ -366,7 +340,7 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
366
340
/// - parameter range: The range in the `Data` to copy.
367
341
/// - warning: This method does not verify that the contents at pointer have enough space to hold the required number of bytes.
368
342
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) )
370
344
}
371
345
372
346
/// Copy the contents of the data into a buffer.
@@ -397,8 +371,10 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
397
371
guard !copyRange. isEmpty else { return 0 }
398
372
399
373
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
+ }
402
378
return copyRange. count
403
379
}
404
380
@@ -499,10 +475,13 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
499
475
500
476
/// Replace a region of bytes in the data with new data.
501
477
///
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.
503
482
/// - 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)
506
485
let cnt = data. count
507
486
let bytes = data. _getUnsafeBytesPointer ( )
508
487
@@ -511,6 +490,68 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
511
490
}
512
491
}
513
492
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
+
514
555
/// Return a new copy of the data in a specified range.
515
556
///
516
557
/// - parameter range: The range to copy.
@@ -526,16 +567,16 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
526
567
///
527
568
/// - parameter options: The options to use for the encoding. Default value is `[]`.
528
569
/// - 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 ) }
531
572
}
532
573
533
574
/// Returns a Base-64 encoded `Data`.
534
575
///
535
576
/// - parameter options: The options to use for the encoding. Default value is `[]`.
536
577
/// - 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 ) }
539
580
}
540
581
541
582
// MARK: -
@@ -556,7 +597,6 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
556
597
return _mapUnmanaged { $0. debugDescription }
557
598
}
558
599
559
- // MARK: -
560
600
561
601
// MARK: -
562
602
// MARK: Index and Subscript
@@ -577,20 +617,12 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
577
617
}
578
618
}
579
619
580
- public subscript( bounds: Range < Int > ) -> MutableRandomAccessSlice < Data > {
620
+ public subscript( bounds: Range < Index > ) -> MutableRandomAccessSlice < Data > {
581
621
get {
582
622
return MutableRandomAccessSlice ( base: self , bounds: bounds)
583
623
}
584
624
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)
594
626
}
595
627
}
596
628
@@ -620,12 +652,14 @@ public struct Data : ReferenceConvertible, CustomStringConvertible, Equatable, H
620
652
public func makeIterator( ) -> Data . Iterator {
621
653
return IndexingIterator ( _elements: self )
622
654
}
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
+ }
623
660
}
624
661
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
+
629
663
630
664
/// Provides bridging functionality for struct Data to class NSData and vice-versa.
631
665
extension Data : _ObjectTypeBridgeable {
@@ -639,11 +673,11 @@ extension Data : _ObjectTypeBridgeable {
639
673
}
640
674
641
675
public static func _forceBridgeFromObjectiveC( _ input: NSData , result: inout Data ? ) {
642
- result = Data ( _bridged : input)
676
+ result = Data ( referencing : input)
643
677
}
644
678
645
679
public static func _conditionallyBridgeFromObjectiveC( _ input: NSData , result: inout Data ? ) -> Bool {
646
- result = Data ( _bridged : input)
680
+ result = Data ( referencing : input)
647
681
return true
648
682
}
649
683
0 commit comments