Merge the swift-corelibs-foundation version of Data in as a single source and correct initializers for copy variants as well as remove defers of _fixLifetime

This commit is contained in:
Philippe Hausler
2016-12-06 10:12:55 -08:00
parent df756f816a
commit 6134083d31

View File

@@ -10,6 +10,26 @@
//
//===----------------------------------------------------------------------===//
#if DEPLOYMENT_RUNTIME_SWIFT
#if os(OSX) || os(iOS)
import Darwin
#elseif os(Linux)
import Glibc
#endif
import CoreFoundation
internal func __NSDataInvokeDeallocatorUnmap(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void {
munmap(mem, length)
}
internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ length: Int) -> Void {
free(mem)
}
#else
@_exported import Foundation // Clang module
@_silgen_name("__NSDataInvokeDeallocatorVM")
@@ -24,6 +44,8 @@ internal func __NSDataInvokeDeallocatorFree(_ mem: UnsafeMutableRawPointer, _ le
@_silgen_name("_NSWriteDataToFile_Swift")
internal func _NSWriteDataToFile_Swift(url: NSURL, data: NSData, options: UInt, error: NSErrorPointer) -> Bool
#endif
public final class _DataStorage {
public enum Backing {
// A mirror of the objective-c implementation that is suitable to inline in swift
@@ -583,6 +605,31 @@ public final class _DataStorage {
_needToZero = true
}
public init(bytes: UnsafeRawPointer?, length: Int) {
precondition(length < _DataStorage.maxSize)
if length == 0 {
_capacity = 0
_length = 0
_needToZero = false
_bytes = nil
} else if _DataStorage.vmOpsThreshold <= length {
_capacity = length
_length = length
_needToZero = true
_bytes = _DataStorage.allocate(length, false)!
_DataStorage.move(_bytes!, bytes, length)
} else {
var capacity = length
if (_DataStorage.vmOpsThreshold <= capacity) {
capacity = NSRoundUpToMultipleOfPageSize(capacity)
}
_length = length
_bytes = _DataStorage.allocate(capacity, false)!
_capacity = capacity
_needToZero = true
_DataStorage.move(_bytes!, bytes, length)
}
}
public init(bytes: UnsafeMutableRawPointer?, length: Int, copy: Bool, deallocator: ((UnsafeMutableRawPointer, Int) -> Void)?) {
precondition(length < _DataStorage.maxSize)
@@ -687,7 +734,8 @@ public final class _DataStorage {
public func withInteriorPointerReference<T>(_ work: (NSData) throws -> T) rethrows -> T {
switch _backing {
case .swift:
return try work(NSData(bytesNoCopy: _bytes!, length: _length, freeWhenDone: false))
let d = _bytes == nil ? NSData() : NSData(bytesNoCopy: _bytes!, length: _length, freeWhenDone: false)
return try work(d)
case .immutable(let d):
return try work(d)
case .mutable(let d):
@@ -829,15 +877,23 @@ internal class _NSSwiftData : NSData {
return NSData(bytes: _backing.bytes, length: _backing.length)
}
#if !DEPLOYMENT_RUNTIME_SWIFT
@objc
func _isCompact() -> Bool {
return true
}
#endif
#if DEPLOYMENT_RUNTIME_SWIFT
override func _providesConcreteBacking() -> Bool {
return true
}
#else
@objc(_providesConcreteBacking)
func _providesConcreteBacking() -> Bool {
return true
}
#endif
}
public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessCollection, MutableCollection, RangeReplaceableCollection {
@@ -859,7 +915,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// When creating a `Data` with the no-copy initializer, you may specify a `Data.Deallocator` to customize the behavior of how the backing store is deallocated.
public enum Deallocator {
/// Use a virtual memory deallocator.
#if !DEPLOYMENT_RUNTIME_SWIFT
case virtualMemory
#endif
/// Use `munmap`.
case unmap
@@ -874,6 +932,20 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
case custom((UnsafeMutableRawPointer, Int) -> Void)
fileprivate var _deallocator : ((UnsafeMutableRawPointer, Int) -> Void)? {
#if DEPLOYMENT_RUNTIME_SWIFT
switch self {
case .unmap:
return { __NSDataInvokeDeallocatorUnmap($0, $1) }
case .free:
return { __NSDataInvokeDeallocatorFree($0, $1) }
case .none:
return nil
case .custom(let b):
return { (ptr, len) in
b(ptr, len)
}
}
#else
switch self {
case .virtualMemory:
return { __NSDataInvokeDeallocatorVM($0, $1) }
@@ -888,6 +960,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
b(ptr, len)
}
}
#endif
}
}
@@ -899,21 +972,21 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - parameter bytes: A pointer to the memory. It will be copied.
/// - parameter count: The number of bytes to copy.
public init(bytes: UnsafeRawPointer, count: Int) {
_backing = _DataStorage(bytes: UnsafeMutableRawPointer(mutating: bytes), length: count, copy: true, deallocator: nil)
_backing = _DataStorage(bytes: bytes, length: count)
}
/// Initialize a `Data` with copied memory content.
///
/// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
public init<SourceType>(buffer: UnsafeBufferPointer<SourceType>) {
_backing = _DataStorage(bytes: UnsafeMutableRawPointer(mutating: buffer.baseAddress), length: MemoryLayout<SourceType>.stride * buffer.count, copy: true, deallocator: nil)
_backing = _DataStorage(bytes: buffer.baseAddress, length: MemoryLayout<SourceType>.stride * buffer.count)
}
/// Initialize a `Data` with copied memory content.
///
/// - parameter buffer: A buffer pointer to copy. The size is calculated from `SourceType` and `buffer.count`.
public init<SourceType>(buffer: UnsafeMutableBufferPointer<SourceType>) {
_backing = _DataStorage(bytes: buffer.baseAddress, length: MemoryLayout<SourceType>.stride * buffer.count, copy: true, deallocator: nil)
_backing = _DataStorage(bytes: buffer.baseAddress, length: MemoryLayout<SourceType>.stride * buffer.count)
}
/// Initialize a `Data` with the contents of an Array.
@@ -921,7 +994,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - parameter bytes: An array of bytes to copy.
public init(bytes: Array<UInt8>) {
_backing = bytes.withUnsafeBufferPointer {
return _DataStorage(bytes: UnsafeMutableRawPointer(mutating: $0.baseAddress), length: $0.count, copy: true, deallocator: nil)
return _DataStorage(bytes: $0.baseAddress, length: $0.count)
}
}
@@ -930,7 +1003,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - parameter bytes: An array of bytes to copy.
public init(bytes: ArraySlice<UInt8>) {
_backing = bytes.withUnsafeBufferPointer {
return _DataStorage(bytes: UnsafeMutableRawPointer(mutating: $0.baseAddress), length: $0.count, copy: true, deallocator: nil)
return _DataStorage(bytes: $0.baseAddress, length: $0.count)
}
}
@@ -968,7 +1041,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - 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(immutableReference: NSData(bytesNoCopy: bytes, length: count, deallocator: whichDeallocator))
_backing = _DataStorage(bytes: bytes, length: count, copy: false, deallocator: whichDeallocator)
}
/// Initialize a `Data` with the contents of a `URL`.
@@ -1015,12 +1088,17 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
///
/// - parameter reference: The instance of `NSData` that you wish to wrap. This instance will be copied by `struct Data`.
public init(referencing reference: NSData) {
#if DEPLOYMENT_RUNTIME_SWIFT
let providesConcreteBacking = reference._providesConcreteBacking()
#else
let providesConcreteBacking = (reference as AnyObject)._providesConcreteBacking?() ?? false
#endif
if providesConcreteBacking {
_backing = _DataStorage(immutableReference: reference.copy() as! NSData)
} else {
_backing = _DataStorage(customReference: reference.copy() as! NSData)
}
}
// -----------------------------------
@@ -1047,8 +1125,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - 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!
defer { _fixLifetime(self)}
let bytes = _backing.bytes ?? UnsafeRawPointer(bitPattern: 0xBAD0)!
let contentPtr = bytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
return try body(contentPtr)
}
@@ -1063,8 +1140,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
if !isKnownUniquelyReferenced(&_backing) {
_backing = _backing.mutableCopy()
}
let mutableBytes = _backing.mutableBytes!
defer { _fixLifetime(self)}
let mutableBytes = _backing.mutableBytes ?? UnsafeMutableRawPointer(bitPattern: 0xBAD0)!
let contentPtr = mutableBytes.bindMemory(to: ContentType.self, capacity: count / MemoryLayout<ContentType>.stride)
return try body(UnsafeMutablePointer(contentPtr))
}
@@ -1079,11 +1155,13 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - 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) {
if count == 0 { return }
memcpy(UnsafeMutableRawPointer(pointer), _backing.bytes!, 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), range.length)
}
@@ -1129,7 +1207,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
}
// MARK: -
#if !DEPLOYMENT_RUNTIME_SWIFT
@inline(__always)
private func _shouldUseNonAtomicWriteReimplementation(options: Data.WritingOptions = []) -> Bool {
@@ -1144,6 +1222,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
return false
}
}
#endif
/// Write the contents of the `Data` to a location.
///
@@ -1152,6 +1231,9 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
/// - throws: An error in the Cocoa domain, if there is an error writing to the `URL`.
public func write(to url: URL, options: Data.WritingOptions = []) throws {
try _backing.withInteriorPointerReference {
#if DEPLOYMENT_RUNTIME_SWIFT
try $0.write(to: url, options: WritingOptions(rawValue: options.rawValue))
#else
if _shouldUseNonAtomicWriteReimplementation(options: options) {
var error : NSError?
if !_NSWriteDataToFile_Swift(url: url._bridgeToObjectiveC(), data: $0, options: options.rawValue, error: &error) {
@@ -1160,6 +1242,7 @@ public struct Data : ReferenceConvertible, Equatable, Hashable, RandomAccessColl
} else {
try $0.write(to: url, options: WritingOptions(rawValue: options.rawValue))
}
#endif
}
}
@@ -1599,7 +1682,14 @@ extension Data {
}
/// Provides bridging functionality for struct Data to class NSData and vice-versa.
extension Data : _ObjectiveCBridgeable {
#if DEPLOYMENT_RUNTIME_SWIFT
internal typealias DataBridgeType = _ObjectTypeBridgeable
#else
internal typealias DataBridgeType = _ObjectiveCBridgeable
#endif
extension Data : DataBridgeType {
@_semantics("convertToObjectiveC")
public func _bridgeToObjectiveC() -> NSData {
return _backing.bridgedReference()