Merge pull request #1283 from phausler/swift-4.0-branch-data_sync
diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
index c580409..df0f6f3 100644
--- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
+++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
@@ -343,6 +343,54 @@
/// a single base directory relative to which user-specific runtime files and other file objects should be placed. This directory is defined by the environment variable $XDG_RUNTIME_DIR.
CF_EXPORT CFStringRef _CFXDGCreateRuntimeDirectoryPath(void);
+
+typedef struct {
+ void *_Nonnull memory;
+ size_t capacity;
+ _Bool onStack;
+} _ConditionalAllocationBuffer;
+
+static inline _Bool _resizeConditionalAllocationBuffer(_ConditionalAllocationBuffer *_Nonnull buffer, size_t amt) {
+#if TARGET_OS_MAC
+ size_t amount = malloc_good_size(amt);
+#else
+ size_t amount = amt;
+#endif
+ if (amount <= buffer->capacity) { return true; }
+ void *newMemory;
+ if (buffer->onStack) {
+ newMemory = malloc(amount);
+ if (newMemory == NULL) { return false; }
+ memcpy(newMemory, buffer->memory, buffer->capacity);
+ buffer->onStack = false;
+ } else {
+ newMemory = realloc(buffer->memory, amount);
+ if (newMemory == NULL) { return false; }
+ }
+ if (newMemory == NULL) { return false; }
+ buffer->memory = newMemory;
+ buffer->capacity = amount;
+ return true;
+}
+
+static inline _Bool _withStackOrHeapBuffer(size_t amount, void (__attribute__((noescape)) ^ _Nonnull applier)(_ConditionalAllocationBuffer *_Nonnull)) {
+ _ConditionalAllocationBuffer buffer;
+#if TARGET_OS_MAC
+ buffer.capacity = malloc_good_size(amount);
+#else
+ buffer.capacity = amount;
+#endif
+ buffer.onStack = (_CFIsMainThread() != 0 ? buffer.capacity < 2048 : buffer.capacity < 512);
+ buffer.memory = buffer.onStack ? alloca(buffer.capacity) : malloc(buffer.capacity);
+ if (buffer.memory == NULL) { return false; }
+ applier(&buffer);
+ if (!buffer.onStack) {
+ free(buffer.memory);
+ }
+ return true;
+}
+
+
_CF_EXPORT_SCOPE_END
#endif /* __COREFOUNDATION_FORSWIFTFOUNDATIONONLY__ */
diff --git a/Foundation/Data.swift b/Foundation/Data.swift
index aa63929..0102662 100644
--- a/Foundation/Data.swift
+++ b/Foundation/Data.swift
@@ -27,6 +27,10 @@
internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) {
free(mem)
}
+
+internal func __NSDataIsCompact(_ data: NSData) -> Bool {
+ return data._isCompact()
+}
#else
@@ -34,6 +38,22 @@
import _SwiftFoundationOverlayShims
import _SwiftCoreFoundationOverlayShims
+internal func __NSDataIsCompact(_ data: NSData) -> Bool {
+ if #available(OSX 10.10, iOS 9.0, tvOS 9.0, watchOS 2.0, *) {
+ return data._isCompact()
+ } else {
+ var compact = true
+ let len = data.length
+ data.enumerateBytes { (_, byteRange, stop) in
+ if byteRange.length != len {
+ compact = false
+ }
+ stop.pointee = true
+ }
+ return compact
+ }
+}
+
@_silgen_name("__NSDataWriteToURL")
internal func __NSDataWriteToURL(_ data: NSData, _ url: NSURL, _ options: UInt, _ error: NSErrorPointer) -> Bool
@@ -98,47 +118,140 @@
public var _needToZero: Bool
public var _deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?
public var _backing: Backing = .swift
+ public var _offset: Int
public var bytes: UnsafeRawPointer? {
@inline(__always)
get {
switch _backing {
case .swift:
- return UnsafeRawPointer(_bytes)
+ return UnsafeRawPointer(_bytes)?.advanced(by: -_offset)
case .immutable:
- return UnsafeRawPointer(_bytes)
+ return UnsafeRawPointer(_bytes)?.advanced(by: -_offset)
case .mutable:
- return UnsafeRawPointer(_bytes)
+ return UnsafeRawPointer(_bytes)?.advanced(by: -_offset)
case .customReference(let d):
- return d.bytes
+ return d.bytes.advanced(by: -_offset)
case .customMutableReference(let d):
- return d.bytes
+ return d.bytes.advanced(by: -_offset)
+ }
+ }
+ }
+
+ @discardableResult
+ public func withUnsafeBytes<Result>(in range: Range<Int>, apply: (UnsafeRawBufferPointer) throws -> Result) rethrows -> Result {
+ switch _backing {
+ case .swift: fallthrough
+ case .immutable: fallthrough
+ case .mutable:
+ return try apply(UnsafeRawBufferPointer(start: _bytes?.advanced(by: range.lowerBound - _offset), count: Swift.min(range.count, _length)))
+ case .customReference(let d):
+ if __NSDataIsCompact(d) {
+ let len = d.length
+ guard len > 0 else {
+ return try apply(UnsafeRawBufferPointer(start: nil, count: 0))
+ }
+ return try apply(UnsafeRawBufferPointer(start: d.bytes.advanced(by: range.lowerBound - _offset), count: Swift.min(range.count, len)))
+ } else {
+ var buffer = UnsafeMutableRawBufferPointer.allocate(count: range.count)
+ defer { buffer.deallocate() }
+ let sliceRange = NSRange(location: range.lowerBound - _offset, length: range.count)
+ var enumerated = 0
+ d.enumerateBytes { (ptr, byteRange, stop) in
+ if NSIntersectionRange(sliceRange, byteRange).length > 0 {
+ let lower = Swift.max(byteRange.location, sliceRange.location)
+ let upper = Swift.min(byteRange.location + byteRange.length, sliceRange.location + sliceRange.length)
+ let offset = lower - byteRange.location
+ let effectiveRange = NSRange(location: lower, length: upper - lower)
+ if effectiveRange == sliceRange {
+ memcpy(buffer.baseAddress!, ptr, effectiveRange.length)
+ stop.pointee = true
+ } else {
+ memcpy(buffer.baseAddress!.advanced(by: enumerated), ptr, effectiveRange.length)
+ }
+ enumerated += byteRange.length
+ } else if sliceRange.location + sliceRange.length < byteRange.location {
+ stop.pointee = true
+ }
+ }
+ return try apply(UnsafeRawBufferPointer(buffer))
+ }
+ case .customMutableReference(let d):
+ if __NSDataIsCompact(d) {
+ let len = d.length
+ guard len > 0 else {
+ return try apply(UnsafeRawBufferPointer(start: nil, count: 0))
+ }
+ return try apply(UnsafeRawBufferPointer(start: d.bytes.advanced(by: range.lowerBound - _offset), count: Swift.min(range.count, len)))
+ } else {
+ var buffer = UnsafeMutableRawBufferPointer.allocate(count: range.count)
+ defer { buffer.deallocate() }
+ let sliceRange = NSRange(location: range.lowerBound - _offset, length: range.count)
+ var enumerated = 0
+ d.enumerateBytes { (ptr, byteRange, stop) in
+ if NSIntersectionRange(sliceRange, byteRange).length > 0 {
+ let lower = Swift.max(byteRange.location, sliceRange.location)
+ let upper = Swift.min(byteRange.location + byteRange.length, sliceRange.location + sliceRange.length)
+ let effectiveRange = NSRange(location: lower, length: upper - lower)
+ if effectiveRange == sliceRange {
+ memcpy(buffer.baseAddress!, ptr, effectiveRange.length)
+ stop.pointee = true
+ } else {
+ memcpy(buffer.baseAddress!.advanced(by: enumerated), ptr, effectiveRange.length)
+ }
+ enumerated += byteRange.length
+ } else if sliceRange.location + sliceRange.length < byteRange.location {
+ stop.pointee = true
+ }
+ }
+ return try apply(UnsafeRawBufferPointer(buffer))
}
}
}
+ @discardableResult
+ public func withUnsafeMutableBytes<Result>(in range: Range<Int>, apply: (UnsafeMutableRawBufferPointer) throws -> Result) rethrows -> Result {
+ switch _backing {
+ case .swift: fallthrough
+ case .mutable:
+ return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length - range.lowerBound)))
+ case .customMutableReference(let d):
+ let len = d.length
+ return try apply(UnsafeMutableRawBufferPointer(start: d.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len - range.lowerBound)))
+ case .immutable(let d):
+ let data = d.mutableCopy() as! NSMutableData
+ _backing = .mutable(data)
+ _bytes = data.mutableBytes
+ return try apply(UnsafeMutableRawBufferPointer(start: _bytes!.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, _length - range.lowerBound)))
+ case .customReference(let d):
+ let data = d.mutableCopy() as! NSMutableData
+ _backing = .customMutableReference(data)
+ let len = data.length
+ return try apply(UnsafeMutableRawBufferPointer(start: data.mutableBytes.advanced(by:range.lowerBound - _offset), count: Swift.min(range.count, len - range.lowerBound)))
+ }
+ }
+
public var mutableBytes: UnsafeMutableRawPointer? {
@inline(__always)
get {
switch _backing {
case .swift:
- return _bytes
+ return _bytes?.advanced(by: -_offset)
case .immutable(let d):
let data = d.mutableCopy() as! NSMutableData
data.length = length
_backing = .mutable(data)
_bytes = data.mutableBytes
- return data.mutableBytes
+ return _bytes?.advanced(by: -_offset)
case .mutable:
- return _bytes
+ return _bytes?.advanced(by: -_offset)
case .customReference(let d):
let data = d.mutableCopy() as! NSMutableData
data.length = length
_backing = .customMutableReference(data)
- _bytes = data.mutableBytes
- return data.mutableBytes
+ return data.mutableBytes.advanced(by: -_offset)
case .customMutableReference(let d):
- return d.mutableBytes
+ return d.mutableBytes.advanced(by: -_offset)
}
}
}
@@ -176,32 +289,34 @@
}
}
- public func enumerateBytes(_ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Data.Index, _ stop: inout Bool) -> Void) {
- var stop: Bool = false
+ public func enumerateBytes(in range: Range<Int>, _ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Data.Index, _ stop: inout Bool) -> Void) {
+ var stopv: Bool = false
+ var data: NSData
switch _backing {
- case .swift:
- block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
- case .immutable:
- block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
- case .mutable:
- block(UnsafeBufferPointer<UInt8>(start: _bytes?.assumingMemoryBound(to: UInt8.self), count: _length), 0, &stop)
+ case .swift: fallthrough
+ case .immutable: fallthrough
+ case .mutable:
+ block(UnsafeBufferPointer<UInt8>(start: _bytes?.advanced(by: range.lowerBound - _offset).assumingMemoryBound(to: UInt8.self), count: Swift.min(range.count, _length)), 0, &stopv)
+ return
case .customReference(let d):
- d.enumerateBytes { (ptr, range, stop) in
- var stopv = false
- let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: range.length)
- block(UnsafeBufferPointer(start: bytePtr, count: range.length), range.location, &stopv)
- if stopv {
- stop.pointee = true
- }
- }
+ data = d
+ break
case .customMutableReference(let d):
- d.enumerateBytes { (ptr, range, stop) in
- var stopv = false
- let bytePtr = ptr.bindMemory(to: UInt8.self, capacity: range.length)
- block(UnsafeBufferPointer(start: bytePtr, count: range.length), range.location, &stopv)
- if stopv {
- stop.pointee = true
- }
+ data = d
+ break
+ }
+ data.enumerateBytes { (ptr, region, stop) in
+ // any region that is not in the range should be skipped
+ guard range.contains(region.lowerBound) || range.contains(region.upperBound) else { return }
+ var regionAdjustment = 0
+ if region.lowerBound < range.lowerBound {
+ regionAdjustment = range.lowerBound - (region.lowerBound - _offset)
+ }
+ let bytePtr = ptr.advanced(by: regionAdjustment).assumingMemoryBound(to: UInt8.self)
+ let effectiveLength = Swift.min((region.location - _offset) + region.length, range.upperBound) - (region.location - _offset)
+ block(UnsafeBufferPointer(start: bytePtr, count: effectiveLength - regionAdjustment), region.location + regionAdjustment - _offset, &stopv)
+ if stopv {
+ stop.pointee = true
}
}
}
@@ -319,7 +434,7 @@
@inline(__always)
public func append(_ bytes: UnsafeRawPointer, length: Int) {
- precondition(length >= 0, "Length of appending bytes must be positive")
+ precondition(length >= 0, "Length of appending bytes must not be negative")
switch _backing {
case .swift:
let origLength = _length
@@ -398,6 +513,43 @@
}
}
+
+ public func get(_ index: Int) -> UInt8 {
+ switch _backing {
+ case .swift: fallthrough
+ case .immutable: fallthrough
+ case .mutable:
+ return _bytes!.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
+ case .customReference(let d):
+ if __NSDataIsCompact(d) {
+ return d.bytes.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
+ } else {
+ var byte: UInt8 = 0
+ d.enumerateBytes { (ptr, range, stop) in
+ if NSLocationInRange(index, range) {
+ let offset = index - range.location - _offset
+ byte = ptr.advanced(by: offset).assumingMemoryBound(to: UInt8.self).pointee
+ stop.pointee = true
+ }
+ }
+ return byte
+ }
+ case .customMutableReference(let d):
+ if __NSDataIsCompact(d) {
+ return d.bytes.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee
+ } else {
+ var byte: UInt8 = 0
+ d.enumerateBytes { (ptr, range, stop) in
+ if NSLocationInRange(index, range) {
+ let offset = index - range.location - _offset
+ byte = ptr.advanced(by: offset).assumingMemoryBound(to: UInt8.self).pointee
+ stop.pointee = true
+ }
+ }
+ return byte
+ }
+ }
+ }
@inline(__always)
public func set(_ index: Int, to value: UInt8) {
@@ -405,7 +557,7 @@
case .swift:
fallthrough
case .mutable:
- _bytes!.advanced(by: index).assumingMemoryBound(to: UInt8.self).pointee = value
+ _bytes!.advanced(by: index - _offset).assumingMemoryBound(to: UInt8.self).pointee = value
default:
var theByte = value
let range = NSRange(location: index, length: 1)
@@ -427,28 +579,29 @@
}
_length = newLength
}
- _DataStorage.move(_bytes!.advanced(by: range.location), bytes!, range.length)
+ _DataStorage.move(_bytes!.advanced(by: range.location - _offset), bytes!, range.length)
case .immutable(let d):
let data = d.mutableCopy() as! NSMutableData
- data.replaceBytes(in: range, withBytes: bytes!)
+ data.replaceBytes(in: NSRange(location: range.location - _offset, length: range.length), withBytes: bytes!)
_backing = .mutable(data)
_length = data.length
_bytes = data.mutableBytes
case .mutable(let d):
- d.replaceBytes(in: range, withBytes: bytes!)
+ d.replaceBytes(in: NSRange(location: range.location - _offset, length: range.length), withBytes: bytes!)
_length = d.length
_bytes = d.mutableBytes
case .customReference(let d):
let data = d.mutableCopy() as! NSMutableData
- data.replaceBytes(in: range, withBytes: bytes!)
+ data.replaceBytes(in: NSRange(location: range.location - _offset, length: range.length), withBytes: bytes!)
_backing = .customMutableReference(data)
case .customMutableReference(let d):
- d.replaceBytes(in: range, withBytes: bytes!)
+ d.replaceBytes(in: NSRange(location: range.location - _offset, length: range.length), withBytes: bytes!)
}
}
@inline(__always)
- public func replaceBytes(in range: NSRange, with replacementBytes: UnsafeRawPointer?, length replacementLength: Int) {
+ public func replaceBytes(in range_: NSRange, with replacementBytes: UnsafeRawPointer?, length replacementLength: Int) {
+ let range = NSRange(location: range_.location - _offset, length: range_.length)
let currentLength = _length
let resultingLength = currentLength - range.length + replacementLength
switch _backing {
@@ -480,12 +633,12 @@
let data = d.mutableCopy() as! NSMutableData
data.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
_backing = .mutable(data)
- _length = replacementLength
+ _length = data.length
_bytes = data.mutableBytes
case .mutable(let d):
d.replaceBytes(in: range, withBytes: replacementBytes, length: replacementLength)
_backing = .mutable(d)
- _length = replacementLength
+ _length = d.length
_bytes = d.mutableBytes
case .customReference(let d):
let data = d.mutableCopy() as! NSMutableData
@@ -497,7 +650,8 @@
}
@inline(__always)
- public func resetBytes(in range: NSRange) {
+ public func resetBytes(in range_: NSRange) {
+ let range = NSRange(location: range_.location - _offset, length: range_.length)
if range.length == 0 { return }
switch _backing {
case .swift:
@@ -546,6 +700,7 @@
_capacity = capacity
_needToZero = !clear
_length = 0
+ _offset = 0
setLength(length)
}
@@ -560,10 +715,12 @@
_bytes = _DataStorage.allocate(capacity, false)!
_capacity = capacity
_needToZero = true
+ _offset = 0
}
public init(bytes: UnsafeRawPointer?, length: Int) {
precondition(length < _DataStorage.maxSize)
+ _offset = 0
if length == 0 {
_capacity = 0
_length = 0
@@ -588,8 +745,9 @@
}
}
- public init(bytes: UnsafeMutableRawPointer?, length: Int, copy: Bool, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?) {
+ public init(bytes: UnsafeMutableRawPointer?, length: Int, copy: Bool, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?, offset: Int) {
precondition(length < _DataStorage.maxSize)
+ _offset = offset
if length == 0 {
_capacity = 0
_length = 0
@@ -630,7 +788,8 @@
}
}
- public init(immutableReference: NSData) {
+ public init(immutableReference: NSData, offset: Int) {
+ _offset = offset
_bytes = UnsafeMutableRawPointer(mutating: immutableReference.bytes)
_capacity = 0
_needToZero = false
@@ -638,7 +797,8 @@
_backing = .immutable(immutableReference)
}
- public init(mutableReference: NSMutableData) {
+ public init(mutableReference: NSMutableData, offset: Int) {
+ _offset = offset
_bytes = mutableReference.mutableBytes
_capacity = 0
_needToZero = false
@@ -646,7 +806,8 @@
_backing = .mutable(mutableReference)
}
- public init(customReference: NSData) {
+ public init(customReference: NSData, offset: Int) {
+ _offset = offset
_bytes = nil
_capacity = 0
_needToZero = false
@@ -654,7 +815,8 @@
_backing = .customReference(customReference)
}
- public init(customMutableReference: NSMutableData) {
+ public init(customMutableReference: NSMutableData, offset: Int) {
+ _offset = offset
_bytes = nil
_capacity = 0
_needToZero = false
@@ -675,30 +837,30 @@
public func mutableCopy(_ range: Range<Int>) -> _DataStorage {
switch _backing {
case .swift:
- return _DataStorage(bytes: _bytes?.advanced(by: range.lowerBound), length: range.count, copy: true, deallocator: nil)
+ return _DataStorage(bytes: _bytes?.advanced(by: range.lowerBound - _offset), length: range.count, copy: true, deallocator: nil, offset: range.lowerBound)
case .immutable(let d):
if range.lowerBound == 0 && range.upperBound == _length {
- return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData, offset: range.lowerBound)
} else {
- return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData, offset: range.lowerBound)
}
case .mutable(let d):
if range.lowerBound == 0 && range.upperBound == _length {
- return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData, offset: range.lowerBound)
} else {
- return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData, offset: range.lowerBound)
}
case .customReference(let d):
if range.lowerBound == 0 && range.upperBound == _length {
- return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData, offset: range.lowerBound)
} else {
- return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData, offset: range.lowerBound)
}
case .customMutableReference(let d):
if range.lowerBound == 0 && range.upperBound == _length {
- return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.mutableCopy() as! NSMutableData, offset: range.lowerBound)
} else {
- return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData)
+ return _DataStorage(mutableReference: d.subdata(with: NSRange(location: range.lowerBound, length: range.count))._bridgeToObjectiveC().mutableCopy() as! NSMutableData, offset: range.lowerBound)
}
}
}
@@ -710,26 +872,26 @@
switch _backing {
case .swift:
- return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
+ return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound - _offset), length: range.count, freeWhenDone: false))
case .immutable(let d):
guard range.lowerBound == 0 && range.upperBound == _length else {
- return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
+ return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound - _offset), length: range.count, freeWhenDone: false))
}
return try work(d)
case .mutable(let d):
guard range.lowerBound == 0 && range.upperBound == _length else {
- return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound), length: range.count, freeWhenDone: false))
+ return try work(NSData(bytesNoCopy: _bytes!.advanced(by: range.lowerBound - _offset), length: range.count, freeWhenDone: false))
}
return try work(d)
case .customReference(let d):
guard range.lowerBound == 0 && range.upperBound == _length else {
- return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound)), length: range.count, freeWhenDone: false))
+ return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound - _offset)), length: range.count, freeWhenDone: false))
}
return try work(d)
case .customMutableReference(let d):
guard range.lowerBound == 0 && range.upperBound == _length else {
- return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound)), length: range.count, freeWhenDone: false))
+ return try work(NSData(bytesNoCopy: UnsafeMutableRawPointer(mutating: d.bytes.advanced(by: range.lowerBound - _offset)), length: range.count, freeWhenDone: false))
}
return try work(d)
}
@@ -766,26 +928,14 @@
}
}
- public var hashValue: Int {
- switch _backing {
- case .customReference(let d):
- return d.hash
- case .customMutableReference(let d):
- return d.hash
- default:
- let len = _length
- return Int(bitPattern: CFHashBytes(_bytes?.assumingMemoryBound(to: UInt8.self), Swift.min(len, 80)))
- }
- }
-
public func subdata(in range: Range<Data.Index>) -> Data {
switch _backing {
case .customReference(let d):
- return d.subdata(with: NSRange(location: range.lowerBound, length: range.count))
+ return d.subdata(with: NSRange(location: range.lowerBound - _offset, length: range.count))
case .customMutableReference(let d):
- return d.subdata(with: NSRange(location: range.lowerBound, length: range.count))
+ return d.subdata(with: NSRange(location: range.lowerBound - _offset, length: range.count))
default:
- return Data(bytes: _bytes!.advanced(by: range.lowerBound), count: range.count)
+ return Data(bytes: _bytes!.advanced(by: range.lowerBound - _offset), count: range.count)
}
}
}
@@ -827,7 +977,7 @@
}
#if !DEPLOYMENT_RUNTIME_SWIFT
- @objc
+ @objc override
func _isCompact() -> Bool {
return true
}
@@ -1015,7 +1165,7 @@
/// - parameter deallocator: Specifies the mechanism to free the indicated buffer, or `.none`.
public init(bytesNoCopy bytes: UnsafeMutableRawPointer, count: Int, deallocator: Deallocator) {
let whichDeallocator = deallocator._deallocator
- _backing = _DataStorage(bytes: bytes, length: count, copy: false, deallocator: whichDeallocator)
+ _backing = _DataStorage(bytes: bytes, length: count, copy: false, deallocator: whichDeallocator, offset: 0)
_sliceRange = 0..<count
}
@@ -1026,7 +1176,7 @@
/// - throws: An error in the Cocoa domain, if `url` cannot be read.
public init(contentsOf url: URL, options: Data.ReadingOptions = []) throws {
let d = try NSData(contentsOf: url, options: ReadingOptions(rawValue: options.rawValue))
- _backing = _DataStorage(immutableReference: d)
+ _backing = _DataStorage(immutableReference: d, offset: 0)
_sliceRange = 0..<d.length
}
@@ -1037,7 +1187,7 @@
/// - parameter options: Encoding options. Default value is `[]`.
public init?(base64Encoded base64String: String, options: Data.Base64DecodingOptions = []) {
if let d = NSData(base64Encoded: base64String, options: Base64DecodingOptions(rawValue: options.rawValue)) {
- _backing = _DataStorage(immutableReference: d)
+ _backing = _DataStorage(immutableReference: d, offset: 0)
_sliceRange = 0..<d.length
} else {
return nil
@@ -1052,7 +1202,7 @@
/// - parameter options: Decoding options. Default value is `[]`.
public init?(base64Encoded base64Data: Data, options: Data.Base64DecodingOptions = []) {
if let d = NSData(base64Encoded: base64Data, options: Base64DecodingOptions(rawValue: options.rawValue)) {
- _backing = _DataStorage(immutableReference: d)
+ _backing = _DataStorage(immutableReference: d, offset: 0)
_sliceRange = 0..<d.length
} else {
return nil
@@ -1073,10 +1223,10 @@
let providesConcreteBacking = (reference as AnyObject)._providesConcreteBacking?() ?? false
#endif
if providesConcreteBacking {
- _backing = _DataStorage(immutableReference: reference.copy() as! NSData)
+ _backing = _DataStorage(immutableReference: reference.copy() as! NSData, offset: 0)
_sliceRange = 0..<reference.length
} else {
- _backing = _DataStorage(customReference: reference.copy() as! NSData)
+ _backing = _DataStorage(customReference: reference.copy() as! NSData, offset: 0)
_sliceRange = 0..<reference.length
}
@@ -1085,40 +1235,30 @@
// slightly faster paths for common sequences
public init<S: Sequence>(_ elements: S) where S.Iterator.Element == UInt8 {
- let underestimatedCount = elements.underestimatedCount
- self.init(count: underestimatedCount)
- var idx = 0
- for byte in elements {
- if idx < underestimatedCount {
- self[idx] = byte
- } else {
- self.append(byte)
+ if elements is Array<UInt8> {
+ self.init(bytes: _identityCast(elements, to: Array<UInt8>.self))
+ } else if elements is ArraySlice<UInt8> {
+ self.init(bytes: _identityCast(elements, to: ArraySlice<UInt8>.self))
+ } else if elements is UnsafeBufferPointer<UInt8> {
+ self.init(buffer: _identityCast(elements, to: UnsafeBufferPointer<UInt8>.self))
+ } else if let buffer = elements as? UnsafeMutableBufferPointer<UInt8> {
+ self.init(buffer: buffer)
+ } else if let data = elements as? Data {
+ let len = data.count
+ let backing = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
+ return _DataStorage(bytes: bytes, length: len)
}
- idx += 1
+ self.init(backing: backing, range: 0..<len)
+ } else {
+ let underestimatedCount = elements.underestimatedCount
+ self.init(count: underestimatedCount)
+
+ let (endIterator, _) = UnsafeMutableBufferPointer(start: _backing._bytes?.assumingMemoryBound(to: UInt8.self), count: underestimatedCount).initialize(from: elements)
+ var iter = endIterator
+ while let byte = iter.next() { self.append(byte) }
}
}
-
- public init(_ bytes: Array<UInt8>) {
- self.init(bytes: bytes)
- }
-
- public init(_ bytes: ArraySlice<UInt8>) {
- self.init(bytes: bytes)
- }
-
- public init(_ buffer: UnsafeBufferPointer<UInt8>) {
- self.init(buffer: buffer)
- }
-
- public init(_ buffer: UnsafeMutableBufferPointer<UInt8>) {
- self.init(buffer: buffer)
- }
-
- public init(_ data: Data) {
- _sliceRange = 0..<data.count
- _backing = data._backing.mutableCopy(data._sliceRange)
- }
-
+
@_versioned
internal init(backing: _DataStorage, range: Range<Index>) {
_backing = backing
@@ -1151,7 +1291,7 @@
}
@inline(__always)
set {
- precondition(count >= 0, "count must be positive")
+ precondition(count >= 0, "count must not be negative")
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy(_sliceRange)
}
@@ -1165,9 +1305,9 @@
/// - warning: The byte pointer argument should not be stored and used outside of the lifetime of the call to the closure.
@inline(__always)
public func withUnsafeBytes<ResultType, ContentType>(_ body: (UnsafePointer<ContentType>) throws -> ResultType) rethrows -> ResultType {
- let bytes = _backing.bytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeRawPointer(bitPattern: 0xBAD0)!
- let contentPtr = bytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
- return try body(contentPtr)
+ return try _backing.withUnsafeBytes(in: _sliceRange) {
+ return try body($0.baseAddress?.assumingMemoryBound(to: ContentType.self) ?? UnsafePointer<ContentType>(bitPattern: 0xBAD0)!)
+ }
}
@@ -1180,9 +1320,9 @@
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy(_sliceRange)
}
- let mutableBytes = _backing.mutableBytes?.advanced(by: _sliceRange.lowerBound) ?? UnsafeMutableRawPointer(bitPattern: 0xBAD0)!
- let contentPtr = mutableBytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
- return try body(UnsafeMutablePointer(contentPtr))
+ return try _backing.withUnsafeMutableBytes(in: _sliceRange) {
+ return try body($0.baseAddress?.assumingMemoryBound(to: ContentType.self) ?? UnsafeMutablePointer<ContentType>(bitPattern: 0xBAD0)!)
+ }
}
// MARK: -
@@ -1195,15 +1335,19 @@
/// - warning: This method does not verify that the contents at pointer have enough space to hold `count` bytes.
@inline(__always)
public func copyBytes(to pointer: UnsafeMutablePointer<UInt8>, count: Int) {
- precondition(count >= 0, "count of bytes to copy must be positive")
+ precondition(count >= 0, "count of bytes to copy must not be negative")
if count == 0 { return }
- memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: _sliceRange.lowerBound), Swift.min(count, _sliceRange.count))
+ _backing.withUnsafeBytes(in: _sliceRange) {
+ memcpy(UnsafeMutableRawPointer(pointer), $0.baseAddress!, Swift.min(count, $0.count))
+ }
}
@inline(__always)
private func _copyBytesHelper(to pointer: UnsafeMutableRawPointer, from range: NSRange) {
if range.length == 0 { return }
- memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!.advanced(by: range.location), Swift.min(range.length, _sliceRange.count))
+ _backing.withUnsafeBytes(in: range.lowerBound..<range.upperBound) {
+ memcpy(UnsafeMutableRawPointer(pointer), $0.baseAddress!, Swift.min(range.length, $0.count))
+ }
}
/// Copy a subset of the contents of the data to a pointer.
@@ -1311,27 +1455,20 @@
/// In some cases, (for example, a `Data` backed by a `dispatch_data_t`, the bytes may be stored discontiguously. In those cases, this function invokes the closure for each contiguous region of bytes.
/// - parameter block: The closure to invoke for each region of data. You may stop the enumeration by setting the `stop` parameter to `true`.
public func enumerateBytes(_ block: (_ buffer: UnsafeBufferPointer<UInt8>, _ byteIndex: Index, _ stop: inout Bool) -> Void) {
- _backing.enumerateBytes(block)
+ _backing.enumerateBytes(in: _sliceRange, block)
}
@inline(__always)
public mutating func append(_ bytes: UnsafePointer<UInt8>, count: Int) {
- precondition(count >= 0, "count must be positive")
if count == 0 { return }
- if !isKnownUniquelyReferenced(&_backing) {
- _backing = _backing.mutableCopy(_sliceRange)
- }
- _backing.append(bytes, length: count)
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + count)
+ append(UnsafeBufferPointer(start: bytes, count: count))
}
@inline(__always)
public mutating func append(_ other: Data) {
- if !isKnownUniquelyReferenced(&_backing) {
- _backing = _backing.mutableCopy(_sliceRange)
+ other.enumerateBytes { (buffer, _, _) in
+ append(buffer)
}
- _backing.append(other._backing, startingAt: other._sliceRange.lowerBound, endingAt: other._sliceRange.upperBound)
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + other.count)
}
/// Append a buffer of bytes to the data.
@@ -1343,22 +1480,26 @@
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy(_sliceRange)
}
- _backing.append(buffer.baseAddress!, length: buffer.count * MemoryLayout<SourceType>.stride)
+ _backing.replaceBytes(in: NSRange(location: _sliceRange.upperBound, length: _backing.length - (_sliceRange.upperBound - _backing._offset)), with: buffer.baseAddress, length: buffer.count * MemoryLayout<SourceType>.stride)
_sliceRange = _sliceRange.lowerBound..<(_sliceRange.upperBound + buffer.count * MemoryLayout<SourceType>.stride)
}
@inline(__always)
public mutating func append<S : Sequence>(contentsOf newElements: S) where S.Iterator.Element == Iterator.Element {
let estimatedCount = newElements.underestimatedCount
- var idx = count
- count += estimatedCount
- for byte in newElements {
- let newIndex = idx + 1
- if newIndex > count {
- count = newIndex
+ guard estimatedCount > 0 else {
+ for byte in newElements {
+ append(byte)
}
- self[idx] = byte
- idx = newIndex
+ return
+ }
+ _withStackOrHeapBuffer(estimatedCount) { allocation in
+ let buffer = UnsafeMutableBufferPointer(start: allocation.pointee.memory.assumingMemoryBound(to: UInt8.self), count: estimatedCount)
+ var (iterator, endPoint) = newElements._copyContents(initializing: buffer)
+ append(buffer.baseAddress!, count: endPoint - buffer.startIndex)
+ while let byte = iterator.next() {
+ append(byte)
+ }
}
}
@@ -1378,16 +1519,15 @@
@inline(__always)
public mutating func resetBytes(in range: Range<Index>) {
// it is worth noting that the range here may be out of bounds of the Data itself (which triggers a growth)
- precondition(range.lowerBound >= 0, "Ranges must be positive bounds")
- precondition(range.upperBound >= 0, "Ranges must be positive bounds")
+ precondition(range.lowerBound >= 0, "Ranges must not be negative bounds")
+ precondition(range.upperBound >= 0, "Ranges must not be negative bounds")
let range = NSMakeRange(range.lowerBound, range.upperBound - range.lowerBound)
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy(_sliceRange)
}
_backing.resetBytes(in: range)
- if _sliceRange.count < range.location + range.length {
- let newLength = range.location + range.length
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + newLength)
+ if _sliceRange.upperBound < range.upperBound {
+ _sliceRange = _sliceRange.lowerBound..<range.upperBound
}
}
@@ -1400,34 +1540,16 @@
/// - parameter data: The replacement data.
@inline(__always)
public mutating func replaceSubrange(_ subrange: Range<Index>, with data: Data) {
- _validateRange(subrange)
- let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
let cnt = data.count
- if !isKnownUniquelyReferenced(&_backing) {
- _backing = _backing.mutableCopy(_sliceRange)
+ data.withUnsafeBytes {
+ replaceSubrange(subrange, with: $0, count: cnt)
}
- let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
- let currentLength = _backing.length
- _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
- return currentLength - nsRange.length + cnt
- }
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
}
@inline(__always)
public mutating func replaceSubrange(_ subrange: CountableRange<Index>, with data: Data) {
- _validateRange(subrange)
- let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
- let cnt = data.count
- if !isKnownUniquelyReferenced(&_backing) {
- _backing = _backing.mutableCopy(_sliceRange)
- }
- let resultingLength = data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) -> Int in
- let currentLength = _backing.length
- _backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
- return currentLength - nsRange.length + cnt
- }
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
+ let range: Range<Int> = subrange.lowerBound..<subrange.upperBound
+ replaceSubrange(range, with: data)
}
/// Replace a region of bytes in the data with new bytes from a buffer.
@@ -1439,17 +1561,8 @@
/// - parameter buffer: The replacement bytes.
@inline(__always)
public mutating func replaceSubrange<SourceType>(_ subrange: Range<Index>, with buffer: UnsafeBufferPointer<SourceType>) {
- _validateRange(subrange)
- let nsRange = NSMakeRange(subrange.lowerBound, subrange.upperBound - subrange.lowerBound)
- let bufferCount = buffer.count * MemoryLayout<SourceType>.stride
-
- if !isKnownUniquelyReferenced(&_backing) {
- _backing = _backing.mutableCopy(_sliceRange)
- }
- let currentLength = _backing.length
- _backing.replaceBytes(in: nsRange, with: buffer.baseAddress, length: bufferCount)
- let resultingLength = currentLength - nsRange.length + bufferCount
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
+ guard buffer.count > 0 else { return }
+ replaceSubrange(subrange, with: buffer.baseAddress!, count: buffer.count * MemoryLayout<SourceType>.stride)
}
/// Replace a region of bytes in the data with new bytes from a collection.
@@ -1460,39 +1573,18 @@
/// - parameter subrange: The range in the data to replace.
/// - parameter newElements: The replacement bytes.
@inline(__always)
- public mutating func replaceSubrange<ByteCollection : Collection>(_ subrange: Range<Index>, with newElements: ByteCollection)
- where ByteCollection.Iterator.Element == Data.Iterator.Element {
- _validateRange(subrange)
- // Calculate this once, it may not be O(1)
- let replacementCount: Int = numericCast(newElements.count)
- let currentCount = self.count
- let subrangeCount = subrange.count
-
- _validateRange(subrange)
-
- let resultCount = currentCount - subrangeCount + replacementCount
- if resultCount != currentCount {
- // This may realloc.
- // 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.
- self.count = resultCount
+ public mutating func replaceSubrange<ByteCollection : Collection>(_ subrange: Range<Index>, with newElements: ByteCollection) where ByteCollection.Iterator.Element == Data.Iterator.Element {
+ _validateRange(subrange)
+ let totalCount: Int = numericCast(newElements.count)
+ _withStackOrHeapBuffer(totalCount) { conditionalBuffer in
+ let buffer = UnsafeMutableBufferPointer(start: conditionalBuffer.pointee.memory.assumingMemoryBound(to: UInt8.self), count: totalCount)
+ var (iterator, index) = newElements._copyContents(initializing: buffer)
+ while let byte = iterator.next() {
+ buffer[index] = byte
+ index = buffer.index(after: index)
}
-
- let shift = resultCount - currentCount
- let start = subrange.lowerBound
-
- self.withUnsafeMutableBytes { (bytes : UnsafeMutablePointer<UInt8>) -> Void in
- if shift != 0 {
- let destination = bytes + start + replacementCount
- let source = bytes + start + subrangeCount
- memmove(destination, source, currentCount - start - subrangeCount)
- }
-
- if replacementCount != 0 {
- let buf = UnsafeMutableBufferPointer(start: bytes + start, count: replacementCount)
- var (it,idx) = newElements._copyContents(initializing: buf)
- precondition(it.next() == nil && idx == buf.endIndex, "newElements iterator returned different count to newElements.count")
- }
- }
+ replaceSubrange(subrange, with: conditionalBuffer.pointee.memory, count: totalCount)
+ }
}
@inline(__always)
@@ -1502,10 +1594,10 @@
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy(_sliceRange)
}
- let currentLength = _backing.length
+ let upper = _sliceRange.upperBound
_backing.replaceBytes(in: nsRange, with: bytes, length: cnt)
- let resultingLength = currentLength - nsRange.length + cnt
- _sliceRange = _sliceRange.lowerBound..<(_sliceRange.lowerBound + resultingLength)
+ let resultingUpper = upper - nsRange.length + cnt
+ _sliceRange = _sliceRange.lowerBound..<resultingUpper
}
/// Return a new copy of the data in a specified range.
@@ -1548,7 +1640,17 @@
/// The hash value for the data.
public var hashValue: Int {
- return _backing.hashValue
+ var hashValue = 0
+ let hashRange: Range<Int> = _sliceRange.lowerBound..<Swift.min(_sliceRange.lowerBound + 80, _sliceRange.upperBound)
+ _withStackOrHeapBuffer(hashRange.count + 1) { buffer in
+ if hashRange.count > 0 {
+ _backing.withUnsafeBytes(in: hashRange) {
+ memcpy(buffer.pointee.memory, $0.baseAddress!, hashRange.count)
+ }
+ }
+ hashValue = Int(bitPattern: CFHashBytes(buffer.pointee.memory.assumingMemoryBound(to: UInt8.self), hashRange.count))
+ }
+ return hashValue
}
@inline(__always)
@@ -1571,7 +1673,7 @@
@inline(__always)
get {
_validateIndex(index)
- return _backing.bytes!.advanced(by: index).assumingMemoryBound(to: UInt8.self).pointee
+ return _backing.get(index)
}
@inline(__always)
set {
@@ -1657,11 +1759,24 @@
}
}
+ public func _copyContents(initializing buffer: UnsafeMutableBufferPointer<UInt8>) -> (Iterator, UnsafeMutableBufferPointer<UInt8>.Index) {
+ guard !isEmpty else { return (makeIterator(), buffer.startIndex) }
+ guard let p = buffer.baseAddress else {
+ preconditionFailure("Attempt to copy contents into nil buffer pointer")
+ }
+ let cnt = count
+ precondition(cnt <= buffer.count, "Insufficient space allocated to copy Data contents")
+
+ withUnsafeBytes { p.initialize(from: $0, count: cnt) }
+
+ return (Iterator(endOf: self), buffer.index(buffer.startIndex, offsetBy: cnt))
+ }
+
/// An iterator over the contents of the data.
///
/// The iterator will increment byte-by-byte.
public func makeIterator() -> Data.Iterator {
- return Iterator(_data: self)
+ return Iterator(self)
}
public struct Iterator : IteratorProtocol {
@@ -1674,11 +1789,18 @@
private var _idx: Data.Index
private let _endIdx: Data.Index
- fileprivate init(_data: Data) {
- self._data = _data
+ fileprivate init(_ data: Data) {
+ _data = data
_buffer = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
- _idx = _data.startIndex
- _endIdx = _data.endIndex
+ _idx = data.startIndex
+ _endIdx = data.endIndex
+ }
+
+ fileprivate init(endOf data: Data) {
+ self._data = data
+ _buffer = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0)
+ _idx = data.endIndex
+ _endIdx = data.endIndex
}
public mutating func next() -> UInt8? {
@@ -1764,7 +1886,7 @@
// Minimal size data is output as an array
if nBytes < 64 {
- children.append((label: "bytes", value: Array(self[0..<nBytes])))
+ children.append((label: "bytes", value: Array(self[startIndex..<Swift.min(nBytes + startIndex, endIndex)])))
}
let m = Mirror(self, children:children, displayStyle: Mirror.DisplayStyle.struct)
@@ -1862,4 +1984,3 @@
}
}
}
-
diff --git a/Foundation/NSData.swift b/Foundation/NSData.swift
index 6dd8048..3066406 100644
--- a/Foundation/NSData.swift
+++ b/Foundation/NSData.swift
@@ -146,6 +146,7 @@
public convenience init(bytesNoCopy bytes: UnsafeMutableRawPointer, length: Int, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)? = nil) {
self.init(bytes: bytes, length: length, copy: false, deallocator: deallocator)
}
+
public convenience init(contentsOfFile path: String, options readOptionsMask: ReadingOptions = []) throws {
let readResult = try NSData.readBytesFromFileWithExtendedAttributes(path, options: readOptionsMask)
self.init(bytes: readResult.bytes, length: readResult.length, copy: false, deallocator: readResult.deallocator)
@@ -380,7 +381,10 @@
}
let length = Int(info.st_size)
-
+ if length == 0 && (info.st_mode & S_IFMT == S_IFREG) {
+ return try readZeroSizeFile(fd)
+ }
+
if options.contains(.alwaysMapped) {
let data = mmap(nil, length, PROT_READ, MAP_PRIVATE, fd, 0)
@@ -414,6 +418,37 @@
free(buffer)
}
}
+
+ internal static func readZeroSizeFile(_ fd: Int32) throws -> NSDataReadResult {
+ let blockSize = 1024 * 1024 // 1MB
+ var data: UnsafeMutableRawPointer? = nil
+ var bytesRead = 0
+ var amt = 0
+
+ repeat {
+ data = realloc(data, bytesRead + blockSize)
+ amt = read(fd, data!.advanced(by: bytesRead), blockSize)
+
+ // Dont continue on EINTR or EAGAIN as the file position may not
+ // have changed, see read(2).
+ if amt < 0 {
+ free(data!)
+ throw NSError(domain: NSPOSIXErrorDomain, code: Int(errno), userInfo: nil)
+ }
+ bytesRead += amt
+ } while amt > 0
+
+ if bytesRead == 0 {
+ free(data!)
+ data = malloc(0)
+ } else {
+ data = realloc(data, bytesRead) // shrink down the allocated block.
+ }
+
+ return NSDataReadResult(bytes: data!, length: bytesRead) { buffer, length in
+ free(buffer)
+ }
+ }
internal func makeTemporaryFile(inDirectory dirPath: String) throws -> (Int32, String) {
let template = dirPath._nsObject.appendingPathComponent("tmp.XXXXXX")
@@ -956,6 +991,19 @@
}
}
+extension NSData {
+ internal func _isCompact() -> Bool {
+ var regions = 0
+ enumerateBytes { (_, _, stop) in
+ regions += 1
+ if regions > 1 {
+ stop.pointee = true
+ }
+ }
+ return regions <= 1
+ }
+}
+
extension NSData : _StructTypeBridgeable {
public typealias _StructType = Data
public func _bridgeToSwift() -> Data {