Merge remote-tracking branch 'origin/master' into swift-4.0-branch
diff --git a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
index d6d28ff..c1e3610 100644
--- a/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
+++ b/CoreFoundation/Base.subproj/ForSwiftFoundationOnly.h
@@ -254,6 +254,8 @@
CF_EXPORT void _CFRuntimeBridgeTypeToClass(CFTypeID type, const void *isa);
+CF_EXPORT CFNumberType _CFNumberGetType2(CFNumberRef number);
+
typedef unsigned char __cf_uuid[16];
typedef char __cf_uuid_string[37];
typedef __cf_uuid _cf_uuid_t;
diff --git a/Foundation/JSONEncoder.swift b/Foundation/JSONEncoder.swift
index 6ab18a3..59a3844 100644
--- a/Foundation/JSONEncoder.swift
+++ b/Foundation/JSONEncoder.swift
@@ -10,6 +10,8 @@
//
//===----------------------------------------------------------------------===//
+import CoreFoundation
+
//===----------------------------------------------------------------------===//
// JSON Encoder
//===----------------------------------------------------------------------===//
@@ -1742,7 +1744,7 @@
}
// TODO: Add a flag to coerce non-boolean numbers into Bools?
- guard number._objCType == .Bool else {
+ guard number._cfTypeID == CFBooleanGetTypeID() else {
throw DecodingError._typeMismatch(at: self.codingPath, expectation: type, reality: value)
}
diff --git a/Foundation/NSCFBoolean.swift b/Foundation/NSCFBoolean.swift
index 90e223b..23577ff 100644
--- a/Foundation/NSCFBoolean.swift
+++ b/Foundation/NSCFBoolean.swift
@@ -78,7 +78,10 @@
override var objCType: UnsafePointer<Int8> {
// This must never be fixed to be "B", although that would
// cause correct old-style archiving when this is unarchived.
- return UnsafePointer<Int8>(bitPattern: UInt(_NSSimpleObjCType.Char.rawValue.value))!
+ func _objCType(_ staticString: StaticString) -> UnsafePointer<Int8> {
+ return UnsafeRawPointer(staticString.utf8Start).assumingMemoryBound(to: Int8.self)
+ }
+ return _objCType("c")
}
internal override func _cfNumberType() -> CFNumberType {
diff --git a/Foundation/NSJSONSerialization.swift b/Foundation/NSJSONSerialization.swift
index ebc7bea..1518b79 100644
--- a/Foundation/NSJSONSerialization.swift
+++ b/Foundation/NSJSONSerialization.swift
@@ -459,8 +459,8 @@
throw NSError(domain: NSCocoaErrorDomain, code: CocoaError.propertyListReadCorrupt.rawValue, userInfo: ["NSDebugDescription" : "Number cannot be infinity or NaN"])
}
- switch num._objCType {
- case .Bool:
+ switch num._cfTypeID {
+ case CFBooleanGetTypeID():
serializeBool(num.boolValue)
default:
writer(_serializationString(for: num))
diff --git a/Foundation/NSKeyedUnarchiver.swift b/Foundation/NSKeyedUnarchiver.swift
index 47fc2f8..b977cc8 100644
--- a/Foundation/NSKeyedUnarchiver.swift
+++ b/Foundation/NSKeyedUnarchiver.swift
@@ -683,10 +683,10 @@
}
open override func decodeBool(forKey key: String) -> Bool {
- guard let result : NSNumber = _decodeValue(forKey: key) else {
+ guard let result : Bool = _decodeValue(forKey: key) else {
return false
}
- return result.boolValue
+ return result
}
open override func decodeInt32(forKey key: String) -> Int32 {
diff --git a/Foundation/NSNumber.swift b/Foundation/NSNumber.swift
index 5cc73a6..c1a712f 100644
--- a/Foundation/NSNumber.swift
+++ b/Foundation/NSNumber.swift
@@ -198,14 +198,17 @@
}
+private struct CFSInt128Struct {
+ var high: Int64
+ var low: UInt64
+}
+
open class NSNumber : NSValue {
typealias CFType = CFNumber
// This layout MUST be the same as CFNumber so that they are bridgeable
private var _base = _CFInfo(typeID: CFNumberGetTypeID())
private var _pad: UInt64 = 0
- internal let _objCType: _NSSimpleObjCType
-
internal var _cfObject: CFType {
return unsafeBitCast(self, to: CFType.self)
}
@@ -230,93 +233,123 @@
}
open override var objCType: UnsafePointer<Int8> {
- return UnsafePointer<Int8>(bitPattern: UInt(_objCType.rawValue.value))!
+ func _objCType(_ staticString: StaticString) -> UnsafePointer<Int8> {
+ return UnsafeRawPointer(staticString.utf8Start).assumingMemoryBound(to: Int8.self)
+ }
+ let numberType = _CFNumberGetType2(_cfObject)
+ switch numberType {
+ case kCFNumberSInt8Type:
+ return _objCType("c")
+ case kCFNumberSInt16Type:
+ return _objCType("s")
+ case kCFNumberSInt32Type:
+ return _objCType("i")
+ case kCFNumberSInt64Type:
+ return _objCType("q")
+ case kCFNumberFloat32Type:
+ return _objCType("f")
+ case kCFNumberFloat64Type:
+ return _objCType("d")
+ case kCFNumberSInt128Type:
+ return _objCType("Q")
+ default:
+ fatalError("unsupported CFNumberType: '\(numberType)'")
+ }
}
deinit {
_CFDeinit(self)
}
- public init(value: Int8) {
- _objCType = .Char
- super.init()
- _CFNumberInitInt8(_cfObject, value)
+ private convenience init(bytes: UnsafeRawPointer, numberType: CFNumberType) {
+ let cfnumber = CFNumberCreate(nil, numberType, bytes)
+ self.init(factory: { unsafeBitCast(cfnumber, to: NSNumber.self) })
}
- public init(value: UInt8) {
- _objCType = .UChar
- super.init()
- _CFNumberInitUInt8(_cfObject, value)
+ public convenience init(value: Int8) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberSInt8Type)
}
- public init(value: Int16) {
- _objCType = .Short
- super.init()
- _CFNumberInitInt16(_cfObject, value)
+ public convenience init(value: UInt8) {
+ var value = Int16(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt16Type)
}
- public init(value: UInt16) {
- _objCType = .UShort
- super.init()
- _CFNumberInitUInt16(_cfObject, value)
+ public convenience init(value: Int16) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberSInt16Type)
}
- public init(value: Int32) {
- _objCType = .Long
- super.init()
- _CFNumberInitInt32(_cfObject, value)
+ public convenience init(value: UInt16) {
+ var value = Int32(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt32Type)
}
- public init(value: UInt32) {
- _objCType = .ULong
- super.init()
- _CFNumberInitUInt32(_cfObject, value)
+ public convenience init(value: Int32) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberSInt32Type)
}
- public init(value: Int) {
- _objCType = .Int
- super.init()
- _CFNumberInitInt(_cfObject, value)
+ public convenience init(value: UInt32) {
+ var value = Int64(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
}
- public init(value: UInt) {
- _objCType = .UInt
- super.init()
- _CFNumberInitUInt(_cfObject, value)
+ public convenience init(value: Int) {
+ var value = value
+ #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+ #elseif arch(i386) || arch(arm)
+ self.init(bytes: &value, numberType: kCFNumberSInt32Type)
+ #endif
}
- public init(value: Int64) {
- _objCType = .LongLong
- super.init()
- _CFNumberInitInt64(_cfObject, value)
+ public convenience init(value: UInt) {
+ #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+ if value > UInt64(Int64.max) {
+ var value = CFSInt128Struct(high: 0, low: UInt64(value))
+ self.init(bytes: &value, numberType: kCFNumberSInt128Type)
+ } else {
+ var value = Int64(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+ }
+ #elseif arch(i386) || arch(arm)
+ var value = Int64(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+ #endif
}
- public init(value: UInt64) {
- _objCType = .ULongLong
- super.init()
- _CFNumberInitUInt64(_cfObject, value)
+ public convenience init(value: Int64) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
}
- public init(value: Float) {
- _objCType = .Float
- super.init()
- _CFNumberInitFloat(_cfObject, value)
+ public convenience init(value: UInt64) {
+ if value > UInt64(Int64.max) {
+ var value = CFSInt128Struct(high: 0, low: UInt64(value))
+ self.init(bytes: &value, numberType: kCFNumberSInt128Type)
+ } else {
+ var value = Int64(value)
+ self.init(bytes: &value, numberType: kCFNumberSInt64Type)
+ }
}
- public init(value: Double) {
- _objCType = .Double
- super.init()
- _CFNumberInitDouble(_cfObject, value)
+ public convenience init(value: Float) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberFloatType)
}
- public init(value: Bool) {
- _objCType = .Bool
- super.init()
- _CFNumberInitBool(_cfObject, value)
+ public convenience init(value: Double) {
+ var value = value
+ self.init(bytes: &value, numberType: kCFNumberDoubleType)
+ }
+
+ public convenience init(value: Bool) {
+ self.init(factory: value._bridgeToObjectiveC)
}
override internal init() {
- _objCType = .Undef
super.init()
}
@@ -381,83 +414,63 @@
}
open var int8Value: Int8 {
- var val: Int8 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int8>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberCharType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var uint8Value: UInt8 {
- var val: UInt8 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt8>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberCharType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var int16Value: Int16 {
- var val: Int16 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int16>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberShortType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var uint16Value: UInt16 {
- var val: UInt16 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt16>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberShortType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var int32Value: Int32 {
- var val: Int32 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int32>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberIntType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var uint32Value: UInt32 {
- var val: UInt32 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt32>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberIntType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var int64Value: Int64 {
- var val: Int64 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Int64>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberLongLongType, value)
- }
- return val
+ var value: Int64 = 0
+ CFNumberGetValue(_cfObject, kCFNumberSInt64Type, &value)
+ return .init(extendingOrTruncating: value)
}
open var uint64Value: UInt64 {
- var val: UInt64 = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<UInt64>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberLongLongType, value)
- }
- return val
+ var value = CFSInt128Struct(high: 0, low: 0)
+ CFNumberGetValue(_cfObject, kCFNumberSInt128Type, &value)
+ return .init(extendingOrTruncating: value.low)
}
open var floatValue: Float {
- var val: Float = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Float>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberFloatType, value)
- }
- return val
+ var value: Float = 0
+ CFNumberGetValue(_cfObject, kCFNumberFloatType, &value)
+ return value
}
open var doubleValue: Double {
- var val: Double = 0
- withUnsafeMutablePointer(to: &val) { (value: UnsafeMutablePointer<Double>) -> Void in
- CFNumberGetValue(_cfObject, kCFNumberDoubleType, value)
- }
- return val
+ var value: Double = 0
+ CFNumberGetValue(_cfObject, kCFNumberDoubleType, &value)
+ return value
}
open var boolValue: Bool {
@@ -503,7 +516,24 @@
}
open func compare(_ otherNumber: NSNumber) -> ComparisonResult {
- return ._fromCF(CFNumberCompare(_cfObject, otherNumber._cfObject, nil))
+ switch (objCType.pointee, otherNumber.objCType.pointee) {
+ case (0x66, _), (_, 0x66), (0x66, 0x66): fallthrough // 'f' float
+ case (0x64, _), (_, 0x64), (0x64, 0x64): // 'd' double
+ let (lhs, rhs) = (doubleValue, otherNumber.doubleValue)
+ if lhs < rhs { return .orderedAscending }
+ if lhs > rhs { return .orderedDescending }
+ return .orderedSame
+ case (0x51, _), (_, 0x51), (0x51, 0x51): // 'q' unsigned long long
+ let (lhs, rhs) = (uint64Value, otherNumber.uint64Value)
+ if lhs < rhs { return .orderedAscending }
+ if lhs > rhs { return .orderedDescending }
+ return .orderedSame
+ case (_, _):
+ let (lhs, rhs) = (int64Value, otherNumber.int64Value)
+ if lhs < rhs { return .orderedAscending }
+ if lhs > rhs { return .orderedDescending }
+ return .orderedSame
+ }
}
open func description(withLocale locale: Locale?) -> String {
@@ -612,7 +642,7 @@
}
}
}
-
+
open override var classForCoder: AnyClass { return NSNumber.self }
}
diff --git a/Foundation/NSValue.swift b/Foundation/NSValue.swift
index 6b255d0..3971b21 100644
--- a/Foundation/NSValue.swift
+++ b/Foundation/NSValue.swift
@@ -154,3 +154,14 @@
}
}
+extension NSValue : _Factory {}
+
+internal protocol _Factory {
+ init(factory: () -> Self)
+}
+
+extension _Factory {
+ init(factory: () -> Self) {
+ self = factory()
+ }
+}
diff --git a/TestFoundation/TestNSNumber.swift b/TestFoundation/TestNSNumber.swift
index 62e16c9..d3ddde8 100644
--- a/TestFoundation/TestNSNumber.swift
+++ b/TestFoundation/TestNSNumber.swift
@@ -21,6 +21,7 @@
static var allTests: [(String, (TestNSNumber) -> () throws -> Void)] {
return [
("test_NumberWithBool", test_NumberWithBool ),
+ ("test_CFBoolean", test_CFBoolean ),
("test_numberWithChar", test_numberWithChar ),
("test_numberWithUnsignedChar", test_numberWithUnsignedChar ),
("test_numberWithShort", test_numberWithShort ),
@@ -41,6 +42,7 @@
("test_compareNumberWithDouble", test_compareNumberWithDouble ),
("test_description", test_description ),
("test_descriptionWithLocale", test_descriptionWithLocale ),
+ ("test_objCType", test_objCType ),
]
}
@@ -977,4 +979,44 @@
XCTAssertEqual(receivedDesc, expectedDesc, "expected \(expectedDesc) but received \(receivedDesc)")
}
}
+
+ func test_objCType() {
+ let objCType: (NSNumber) -> UnicodeScalar = { number in
+ return UnicodeScalar(UInt8(number.objCType.pointee))
+ }
+
+ XCTAssertEqual("c" /* 0x63 */, objCType(NSNumber(value: true)))
+
+ XCTAssertEqual("c" /* 0x63 */, objCType(NSNumber(value: Int8.max)))
+ XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: UInt8(Int8.max))))
+ XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: UInt8(Int8.max) + 1)))
+
+ XCTAssertEqual("s" /* 0x73 */, objCType(NSNumber(value: Int16.max)))
+ XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: UInt16(Int16.max))))
+ XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: UInt16(Int16.max) + 1)))
+
+ XCTAssertEqual("i" /* 0x69 */, objCType(NSNumber(value: Int32.max)))
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt32(Int32.max))))
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt32(Int32.max) + 1)))
+
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: Int64.max)))
+ // When value is lower equal to `Int64.max`, it returns 'q' even if using `UInt64`
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt64(Int64.max))))
+ XCTAssertEqual("Q" /* 0x51 */, objCType(NSNumber(value: UInt64(Int64.max) + 1)))
+
+ // Depends on architectures
+ #if arch(x86_64) || arch(arm64) || arch(s390x) || arch(powerpc64) || arch(powerpc64le)
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: Int.max)))
+ // When value is lower equal to `Int.max`, it returns 'q' even if using `UInt`
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt(Int.max))))
+ XCTAssertEqual("Q" /* 0x51 */, objCType(NSNumber(value: UInt(Int.max) + 1)))
+ #elseif arch(i386) || arch(arm)
+ XCTAssertEqual("i" /* 0x71 */, objCType(NSNumber(value: Int.max)))
+ XCTAssertEqual("q" /* 0x71 */, objCType(NSNumber(value: UInt(Int.max))))
+ XCTAssertEqual("q" /* 0x51 */, objCType(NSNumber(value: UInt(Int.max) + 1)))
+ #endif
+
+ XCTAssertEqual("f" /* 0x66 */, objCType(NSNumber(value: Float.greatestFiniteMagnitude)))
+ XCTAssertEqual("d" /* 0x64 */, objCType(NSNumber(value: Double.greatestFiniteMagnitude)))
+ }
}
diff --git a/TestFoundation/TestNSPredicate.swift b/TestFoundation/TestNSPredicate.swift
index 641d605..4e88e33 100644
--- a/TestFoundation/TestNSPredicate.swift
+++ b/TestFoundation/TestNSPredicate.swift
@@ -101,6 +101,9 @@
let predicateA = NSPredicate(value: true)
let predicateB = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateA)) as! NSPredicate
XCTAssertEqual(predicateA, predicateB, "Archived then unarchived uuid must be equal.")
+ let predicateC = NSPredicate(value: false)
+ let predicateD = NSKeyedUnarchiver.unarchiveObject(with: NSKeyedArchiver.archivedData(withRootObject: predicateC)) as! NSPredicate
+ XCTAssertEqual(predicateC, predicateD, "Archived then unarchived uuid must be equal.")
}
func test_copy() {