Skip to content

Commit 4c2d939

Browse files
committed
Actually implement NSData the way it is on Darwin.
1 parent 0fa5580 commit 4c2d939

File tree

1 file changed

+72
-11
lines changed

1 file changed

+72
-11
lines changed

Foundation/NSData.swift

Lines changed: 72 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -271,11 +271,13 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
271271

272272
/// The number of bytes contained by the data object.
273273
open var length: Int {
274+
requireFunnelOverridden()
274275
return CFDataGetLength(_cfObject)
275276
}
276277

277278
/// A pointer to the data object's contents.
278279
open var bytes: UnsafeRawPointer {
280+
requireFunnelOverridden()
279281
guard let bytePtr = CFDataGetBytePtr(_cfObject) else {
280282
//This could occure on empty data being encoded.
281283
//TODO: switch with nil when signature is fixed
@@ -517,14 +519,29 @@ open class NSData : NSObject, NSCopying, NSMutableCopying, NSSecureCoding {
517519
// MARK: - Bytes
518520
/// Copies a number of bytes from the start of the data object into a given buffer.
519521
open func getBytes(_ buffer: UnsafeMutableRawPointer, length: Int) {
520-
let bytePtr = buffer.bindMemory(to: UInt8.self, capacity: length)
521-
CFDataGetBytes(_cfObject, CFRangeMake(0, length), bytePtr)
522+
if funnelsAreAbstract {
523+
let actualCount = Swift.min(length, self.length)
524+
let sourceBuffer = UnsafeRawBufferPointer(start: bytes, count: actualCount)
525+
let destinationBuffer = UnsafeMutableRawBufferPointer(start: buffer, count: actualCount)
526+
sourceBuffer.copyBytes(to: destinationBuffer)
527+
} else {
528+
let bytePtr = buffer.bindMemory(to: UInt8.self, capacity: length)
529+
CFDataGetBytes(_cfObject, CFRangeMake(0, length), bytePtr)
530+
}
522531
}
523532

524533
/// Copies a range of bytes from the data object into a given buffer.
525534
open func getBytes(_ buffer: UnsafeMutableRawPointer, range: NSRange) {
526-
let bytePtr = buffer.bindMemory(to: UInt8.self, capacity: range.length)
527-
CFDataGetBytes(_cfObject, CFRangeMake(range.location, range.length), bytePtr)
535+
if funnelsAreAbstract {
536+
precondition(range.location >= 0 && range.length >= 0)
537+
let actualCount = Swift.min(range.length, self.length - range.location)
538+
let sourceBuffer = UnsafeRawBufferPointer(start: bytes.advanced(by: range.location), count: actualCount)
539+
let destinationBuffer = UnsafeMutableRawBufferPointer(start: buffer, count: actualCount)
540+
sourceBuffer.copyBytes(to: destinationBuffer)
541+
} else {
542+
let bytePtr = buffer.bindMemory(to: UInt8.self, capacity: range.length)
543+
CFDataGetBytes(_cfObject, CFRangeMake(range.location, range.length), bytePtr)
544+
}
528545
}
529546

530547
/// Returns a new data object containing the data object's bytes that fall within the limits specified by a given range.
@@ -927,15 +944,18 @@ open class NSMutableData : NSData {
927944
// MARK: - Funnel Methods
928945
/// A pointer to the data contained by the mutable data object.
929946
open var mutableBytes: UnsafeMutableRawPointer {
947+
requireFunnelOverridden()
930948
return UnsafeMutableRawPointer(CFDataGetMutableBytePtr(_cfMutableObject))
931949
}
932950

933951
/// The number of bytes contained in the mutable data object.
934952
open override var length: Int {
935953
get {
954+
requireFunnelOverridden()
936955
return CFDataGetLength(_cfObject)
937956
}
938957
set {
958+
requireFunnelOverridden()
939959
CFDataSetLength(_cfMutableObject, newValue)
940960
}
941961
}
@@ -948,8 +968,15 @@ open class NSMutableData : NSData {
948968
// MARK: - Mutability
949969
/// Appends to the data object a given number of bytes from a given buffer.
950970
open func append(_ bytes: UnsafeRawPointer, length: Int) {
951-
let bytePtr = bytes.bindMemory(to: UInt8.self, capacity: length)
952-
CFDataAppendBytes(_cfMutableObject, bytePtr, length)
971+
guard length > 0 else { return }
972+
973+
if funnelsAreAbstract {
974+
self.length += length
975+
UnsafeRawBufferPointer(start: bytes, count: length).copyBytes(to: UnsafeMutableRawBufferPointer(start: mutableBytes, count: length))
976+
} else {
977+
let bytePtr = bytes.bindMemory(to: UInt8.self, capacity: length)
978+
CFDataAppendBytes(_cfMutableObject, bytePtr, length)
979+
}
953980
}
954981

955982
/// Appends the content of another data object to the data object.
@@ -962,13 +989,21 @@ open class NSMutableData : NSData {
962989

963990
/// Increases the length of the data object by a given number of bytes.
964991
open func increaseLength(by extraLength: Int) {
965-
CFDataSetLength(_cfMutableObject, CFDataGetLength(_cfObject) + extraLength)
992+
if funnelsAreAbstract {
993+
self.length += extraLength
994+
} else {
995+
CFDataSetLength(_cfMutableObject, CFDataGetLength(_cfObject) + extraLength)
996+
}
966997
}
967998

968999
/// Replaces with a given set of bytes a given range within the contents of the data object.
9691000
open func replaceBytes(in range: NSRange, withBytes bytes: UnsafeRawPointer) {
970-
let bytePtr = bytes.bindMemory(to: UInt8.self, capacity: length)
971-
CFDataReplaceBytes(_cfMutableObject, CFRangeMake(range.location, range.length), bytePtr, length)
1001+
if funnelsAreAbstract {
1002+
replaceBytes(in: range, withBytes: bytes, length: range.length)
1003+
} else {
1004+
let bytePtr = bytes.bindMemory(to: UInt8.self, capacity: length)
1005+
CFDataReplaceBytes(_cfMutableObject, CFRangeMake(range.location, range.length), bytePtr, length)
1006+
}
9721007
}
9731008

9741009
/// Replaces with zeroes the contents of the data object in a given range.
@@ -986,8 +1021,22 @@ open class NSMutableData : NSData {
9861021

9871022
/// Replaces with a given set of bytes a given range within the contents of the data object.
9881023
open func replaceBytes(in range: NSRange, withBytes replacementBytes: UnsafeRawPointer?, length replacementLength: Int) {
989-
let bytePtr = replacementBytes?.bindMemory(to: UInt8.self, capacity: replacementLength)
990-
CFDataReplaceBytes(_cfMutableObject, CFRangeMake(range.location, range.length), bytePtr, replacementLength)
1024+
precondition(range.location + range.length <= self.length)
1025+
if funnelsAreAbstract {
1026+
let delta = replacementLength - range.length
1027+
if delta != 0 {
1028+
let originalLength = self.length
1029+
self.length += delta
1030+
1031+
if delta > 0 {
1032+
UnsafeRawBufferPointer(start: mutableBytes.advanced(by: range.location), count: originalLength).copyBytes(to: UnsafeMutableRawBufferPointer(start: mutableBytes.advanced(by: range.location + range.length), count: originalLength))
1033+
}
1034+
}
1035+
UnsafeRawBufferPointer(start: replacementBytes, count: replacementLength).copyBytes(to: UnsafeMutableRawBufferPointer(start: mutableBytes.advanced(by: range.location), count: replacementLength))
1036+
} else {
1037+
let bytePtr = replacementBytes?.bindMemory(to: UInt8.self, capacity: replacementLength)
1038+
CFDataReplaceBytes(_cfMutableObject, CFRangeMake(range.location, range.length), bytePtr, replacementLength)
1039+
}
9911040
}
9921041
}
9931042

@@ -1046,3 +1095,15 @@ internal func _CFSwiftDataAppendBytes(_ data: CFTypeRef, _ buffer: UnsafeRawPoin
10461095
internal func _CFSwiftDataReplaceBytes(_ data: CFTypeRef, _ range: CFRange, _ buffer: UnsafeRawPointer?, _ count: CFIndex) {
10471096
(data as! NSMutableData).replaceBytes(in: NSMakeRange(range.location, range.length), withBytes: buffer, length: count)
10481097
}
1098+
1099+
extension NSData {
1100+
var funnelsAreAbstract: Bool {
1101+
return type(of: self) != NSData.self && type(of: self) != NSMutableData.self
1102+
}
1103+
1104+
func requireFunnelOverridden() {
1105+
if funnelsAreAbstract {
1106+
NSRequiresConcreteImplementation()
1107+
}
1108+
}
1109+
}

0 commit comments

Comments
 (0)