Permalink
Browse files

Improve consistency in NSNumber bridging

This makes sure casts of NaN succeed, and init(exactly: NaN) fails.
  • Loading branch information...
natecook1000 committed Nov 29, 2017
1 parent 5edbefc commit 956e793ef0814c939ef150536e5d207914eefc91
@@ -434,9 +434,17 @@ extension Float : _ObjectiveCBridgeable {
}
public init?(exactly number: NSNumber) {
guard let value = Double(exactly: number) else { return nil }
guard let result = Float(exactly: value) else { return nil }
self = result
let type = number.objCType.pointee
if type == 0x49 || type == 0x4c || type == 0x51 {
guard let result = Float(exactly: number.uint64Value) else { return nil }
self = result
} else if type == 0x69 || type == 0x6c || type == 0x71 {
guard let result = Float(exactly: number.int64Value) else { return nil }
self = result
} else {
guard let result = Float(exactly: number.doubleValue) else { return nil }
self = result
}
}
@_semantics("convertToObjectiveC")
@@ -451,25 +459,12 @@ extension Float : _ObjectiveCBridgeable {
}
public static func _conditionallyBridgeFromObjectiveC(_ x: NSNumber, result: inout Float?) -> Bool {
guard let value = Double(exactly: x) else { return false }
guard !value.isNaN else {
result = Float.nan
return true
}
guard !value.isInfinite else {
if value.sign == .minus {
result = -Float.infinity
} else {
result = Float.infinity
}
if x.floatValue.isNaN {
result = x.floatValue
return true
}
guard Swift.abs(value) <= Double(Float.greatestFiniteMagnitude) else {
return false
}
result = Float(value)
return true
result = Float(exactly: x)
return result != nil
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSNumber?) -> Float {
@@ -499,7 +494,10 @@ extension Double : _ObjectiveCBridgeable {
guard let result = Double(exactly: number.int64Value) else { return nil }
self = result
} else {
self = number.doubleValue
// All other integer types and single-precision floating points will
// fit in a `Double` without truncation.
guard let result = Double(exactly: number.doubleValue) else { return nil }
self = result
}
}
@@ -515,9 +513,12 @@ extension Double : _ObjectiveCBridgeable {
}
public static func _conditionallyBridgeFromObjectiveC(_ x: NSNumber, result: inout Double?) -> Bool {
guard let value = Double(exactly: x) else { return false }
result = value
return true
if x.doubleValue.isNaN {
result = x.doubleValue
return true
}
result = Double(exactly: x)
return result != nil
}
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSNumber?) -> Double {
@@ -24,58 +24,6 @@ import Foundation
import CoreGraphics
import FoundationBridgeObjC
extension Float {
init?(reasonably value: Float) {
self = value
}
init?(reasonably value: Double) {
guard !value.isNaN else {
self = Float.nan
return
}
guard !value.isInfinite else {
if value.sign == .minus {
self = -Float.infinity
} else {
self = Float.infinity
}
return
}
guard abs(value) <= Double(Float.greatestFiniteMagnitude) else {
return nil
}
self = Float(value)
}
}
extension Double {
init?(reasonably value: Float) {
guard !value.isNaN else {
self = Double.nan
return
}
guard !value.isInfinite else {
if value.sign == .minus {
self = -Double.infinity
} else {
self = Double.infinity
}
return
}
self = Double(value)
}
init?(reasonably value: Double) {
self = value
}
}
var nsNumberBridging = TestSuite("NSNumberBridging")
func testFloat(_ lhs: Float?, _ rhs: Float?, file: String = #file, line: UInt = #line) {
@@ -476,12 +424,7 @@ func testNSNumberBridgeFromInt32() {
let float = (number!) as? Float
let expectedFloat = Float(exactly: int32!)
// these are disabled because of https://bugs.swift.org/browse/SR-4634
if (int32! != Int32.min && int32! != Int32.max &&
int32! != Int32.min + 1 && int32! != Int32.max - 1) {
testFloat(expectedFloat, float)
}
testFloat(expectedFloat, float)
let double = (number!) as? Double
let expectedDouble = Double(int32!)
@@ -520,12 +463,9 @@ func testNSNumberBridgeFromUInt32() {
expectEqual(UInt(exactly: interestingValue), uint)
let float = (number!) as? Float
let expectedFloat = Float(uint32!)
// these are disabled because of https://bugs.swift.org/browse/SR-4634
if (uint32! != UInt32.max && uint32! != UInt32.max - UInt32(1)) {
testFloat(expectedFloat, float)
}
let expectedFloat = Float(exactly: uint32!)
testFloat(expectedFloat, float)
let double = (number!) as? Double
let expectedDouble = Double(uint32!)
testDouble(expectedDouble, double)
@@ -703,12 +643,22 @@ func testNSNumberBridgeFromFloat() {
expectEqual(UInt(exactly: interestingValue), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = Double(interestingValue)
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)
@@ -743,12 +693,22 @@ func testNSNumberBridgeFromDouble() {
expectEqual(UInt(exactly: interestingValue), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = interestingValue
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)
@@ -783,12 +743,22 @@ func testNSNumberBridgeFromCGFloat() {
expectEqual(UInt(exactly: interestingValue.native), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue.native)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue.native)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = Double(interestingValue)
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue.native)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)
@@ -18,58 +18,6 @@ import StdlibUnittest
import Foundation
import CoreGraphics
extension Float {
init?(reasonably value: Float) {
self = value
}
init?(reasonably value: Double) {
guard !value.isNaN else {
self = Float.nan
return
}
guard !value.isInfinite else {
if value.sign == .minus {
self = -Float.infinity
} else {
self = Float.infinity
}
return
}
guard abs(value) <= Double(Float.greatestFiniteMagnitude) else {
return nil
}
self = Float(value)
}
}
extension Double {
init?(reasonably value: Float) {
guard !value.isNaN else {
self = Double.nan
return
}
guard !value.isInfinite else {
if value.sign == .minus {
self = -Double.infinity
} else {
self = Double.infinity
}
return
}
self = Double(value)
}
init?(reasonably value: Double) {
self = value
}
}
var nsNumberBridging = TestSuite("NSNumberBridgingValidation")
func testFloat(_ lhs: Float?, _ rhs: Float?, file: String = #file, line: UInt = #line) {
@@ -697,12 +645,22 @@ func testNSNumberBridgeFromFloat() {
expectEqual(UInt(exactly: interestingValue), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = Double(interestingValue)
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)
@@ -737,12 +695,22 @@ func testNSNumberBridgeFromDouble() {
expectEqual(UInt(exactly: interestingValue), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = interestingValue
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)
@@ -777,12 +745,22 @@ func testNSNumberBridgeFromCGFloat() {
expectEqual(UInt(exactly: interestingValue.native), uint)
let float = (number!) as? Float
let expectedFloat = Float(reasonably: interestingValue.native)
testFloat(expectedFloat, float)
let expectedFloat = Float(exactly: interestingValue.native)
if interestingValue.isNaN {
expectTrue(float?.isNaN == true)
expectNil(expectedFloat)
} else {
testFloat(expectedFloat, float)
}
let double = (number!) as? Double
let expectedDouble = Double(interestingValue)
testDouble(expectedDouble, double)
let expectedDouble = Double(exactly: interestingValue.native)
if interestingValue.isNaN {
expectTrue(double?.isNaN == true)
expectNil(expectedDouble)
} else {
testDouble(expectedDouble, double)
}
}
let bridged = interestingValue as NSNumber
testNumber(bridged)

0 comments on commit 956e793

Please sign in to comment.