Skip to content

Commit 08afbe6

Browse files
committed
Improve consistency in NSNumber bridging
1 parent d33f036 commit 08afbe6

File tree

2 files changed

+59
-96
lines changed

2 files changed

+59
-96
lines changed

Foundation/NSNumber.swift

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -423,9 +423,17 @@ extension Float : _ObjectTypeBridgeable {
423423
}
424424

425425
public init?(exactly number: NSNumber) {
426-
guard let value = Double(exactly: number) else { return nil }
427-
guard let result = Float(exactly: value) else { return nil }
428-
self = result
426+
let type = number.objCType.pointee
427+
if type == 0x49 || type == 0x4c || type == 0x51 {
428+
guard let result = Float(exactly: number.uint64Value) else { return nil }
429+
self = result
430+
} else if type == 0x69 || type == 0x6c || type == 0x71 {
431+
guard let result = Float(exactly: number.int64Value) else { return nil }
432+
self = result
433+
} else {
434+
guard let result = Float(exactly: number.doubleValue) else { return nil }
435+
self = result
436+
}
429437
}
430438

431439
public func _bridgeToObjectiveC() -> NSNumber {
@@ -437,25 +445,12 @@ extension Float : _ObjectTypeBridgeable {
437445
}
438446

439447
public static func _conditionallyBridgeFromObjectiveC(_ x: NSNumber, result: inout Float?) -> Bool {
440-
guard let value = Double(exactly: x) else { return false }
441-
guard !value.isNaN else {
442-
result = Float.nan
443-
return true
444-
}
445-
guard !value.isInfinite else {
446-
if value.sign == .minus {
447-
result = -Float.infinity
448-
} else {
449-
result = Float.infinity
450-
}
448+
if x.floatValue.isNaN {
449+
result = x.floatValue
451450
return true
452451
}
453-
guard Swift.abs(value) <= Double(Float.greatestFiniteMagnitude) else {
454-
return false
455-
}
456-
457-
result = Float(value)
458-
return true
452+
result = Float(exactly: x)
453+
return result != nil
459454
}
460455

461456
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSNumber?) -> Float {
@@ -485,7 +480,10 @@ extension Double : _ObjectTypeBridgeable {
485480
guard let result = Double(exactly: number.int64Value) else { return nil }
486481
self = result
487482
} else {
488-
self = number.doubleValue
483+
// All other integer types and single-precision floating points will
484+
// fit in a `Double` without truncation.
485+
guard let result = Double(exactly: number.doubleValue) else { return nil }
486+
self = result
489487
}
490488
}
491489

@@ -498,9 +496,12 @@ extension Double : _ObjectTypeBridgeable {
498496
}
499497

500498
public static func _conditionallyBridgeFromObjectiveC(_ x: NSNumber, result: inout Double?) -> Bool {
501-
guard let value = Double(exactly: x) else { return false }
502-
result = value
503-
return true
499+
if x.doubleValue.isNaN {
500+
result = x.doubleValue
501+
return true
502+
}
503+
result = Double(exactly: x)
504+
return result != nil
504505
}
505506

506507
public static func _unconditionallyBridgeFromObjectiveC(_ source: NSNumber?) -> Double {

TestFoundation/TestNSNumberBridging.swift

Lines changed: 34 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -245,14 +245,7 @@ class TestNSNumberBridging : XCTestCase {
245245

246246
let float = Float(exactly: number!)
247247
let expectedFloat = Float(exactly: int32!)
248-
if int32! != Int32.min + 1 && int32! < Int32.max - 1 {
249-
testFloat(expectedFloat, float)
250-
} else {
251-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
252-
// https://bugs.swift.org/browse/SR-6322
253-
// XCTAssertNil(float)
254-
// XCTAssertNil(expectedFloat)
255-
}
248+
testFloat(expectedFloat, float)
256249

257250
let double = Double(exactly: number!)
258251
let expectedDouble = Double(exactly: int32!)
@@ -292,14 +285,7 @@ class TestNSNumberBridging : XCTestCase {
292285

293286
let float = Float(exactly: number!)
294287
let expectedFloat = Float(exactly: uint32!)
295-
if uint32! < UInt32.max - 1 {
296-
testFloat(expectedFloat, float)
297-
} else {
298-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
299-
// https://bugs.swift.org/browse/SR-6322
300-
// XCTAssertNil(float)
301-
// XCTAssertNil(expectedFloat)
302-
}
288+
testFloat(expectedFloat, float)
303289

304290
let double = Double(exactly: number!)
305291
let expectedDouble = Double(exactly: uint32!)
@@ -338,17 +324,12 @@ class TestNSNumberBridging : XCTestCase {
338324
XCTAssertEqual(UInt(exactly: interestingValue), uint)
339325

340326
let float = Float(exactly: number!)
327+
let expectedFloat = Float(exactly: int64!)
328+
testFloat(expectedFloat, float)
329+
341330
let double = Double(exactly: number!)
342-
if int64! != Int64.min + 1 && int64! < Int64.max - 1 {
343-
// Note: Double/Float(exactly: Int64.min) != nil
344-
XCTAssertEqual(Float(interestingValue), float)
345-
XCTAssertEqual(Double(interestingValue), double)
346-
} else {
347-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
348-
// https://bugs.swift.org/browse/SR-6322
349-
// XCTAssertNil(float)
350-
// XCTAssertNil(double)
351-
}
331+
let expectedDouble = Double(exactly: int64!)
332+
testDouble(expectedDouble, double)
352333
}
353334
let bridged = interestingValue._bridgeToObjectiveC()
354335
testNumber(bridged)
@@ -383,16 +364,12 @@ class TestNSNumberBridging : XCTestCase {
383364
XCTAssertEqual(UInt(exactly: interestingValue), uint)
384365

385366
let float = Float(exactly: number!)
367+
let expectedFloat = Float(exactly: uint64!)
368+
testFloat(expectedFloat, float)
369+
386370
let double = Double(exactly: number!)
387-
if uint64! < UInt64.max - 1 {
388-
XCTAssertEqual(Float(interestingValue), float)
389-
XCTAssertEqual(Double(interestingValue), double)
390-
} else {
391-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
392-
// https://bugs.swift.org/browse/SR-6322
393-
// XCTAssertNil(float)
394-
// XCTAssertNil(double)
395-
}
371+
let expectedDouble = Double(exactly: uint64!)
372+
testDouble(expectedDouble, double)
396373
}
397374
let bridged = interestingValue._bridgeToObjectiveC()
398375
testNumber(bridged)
@@ -427,17 +404,12 @@ class TestNSNumberBridging : XCTestCase {
427404
XCTAssertEqual(UInt(exactly: interestingValue), uint)
428405

429406
let float = Float(exactly: number!)
407+
let expectedFloat = Float(exactly: int!)
408+
testFloat(expectedFloat, float)
409+
430410
let double = Double(exactly: number!)
431-
if int! != Int.min + 1 && int! < Int.max - 1 {
432-
// Double/Float(exactly: Int.min) != nil
433-
XCTAssertEqual(Float(interestingValue), float)
434-
XCTAssertEqual(Double(interestingValue), double)
435-
} else {
436-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
437-
// https://bugs.swift.org/browse/SR-6322
438-
// XCTAssertNil(float)
439-
// XCTAssertNil(double)
440-
}
411+
let expectedDouble = Double(exactly: int!)
412+
testDouble(expectedDouble, double)
441413
}
442414
let bridged = interestingValue._bridgeToObjectiveC()
443415
testNumber(bridged)
@@ -472,16 +444,12 @@ class TestNSNumberBridging : XCTestCase {
472444
XCTAssertEqual(UInt(exactly: interestingValue), uint)
473445

474446
let float = Float(exactly: number!)
447+
let expectedFloat = Float(exactly: uint!)
448+
testFloat(expectedFloat, float)
449+
475450
let double = Double(exactly: number!)
476-
if uint! < UInt.max - 1 {
477-
XCTAssertEqual(Float(interestingValue), float)
478-
XCTAssertEqual(Double(interestingValue), double)
479-
} else {
480-
// FIXME: Exact conversions to NSNumber succeeding incorrectly
481-
// https://bugs.swift.org/browse/SR-6322
482-
// XCTAssertNil(float)
483-
// XCTAssertNil(double)
484-
}
451+
let expectedDouble = Double(exactly: uint!)
452+
testDouble(expectedDouble, double)
485453
}
486454
let bridged = interestingValue._bridgeToObjectiveC()
487455
testNumber(bridged)
@@ -515,16 +483,13 @@ class TestNSNumberBridging : XCTestCase {
515483
let uint = UInt(exactly: number!)
516484
XCTAssertEqual(UInt(exactly: interestingValue), uint)
517485

518-
let float = Float(truncating: number!)
519-
let expectedFloat = interestingValue
486+
let float = Float(exactly: number!)
487+
let expectedFloat = Float(exactly: interestingValue)
520488
testFloat(expectedFloat, float)
521-
522-
// FIXME: Double.nan doesn't round-trip through NSNumber
523-
if !interestingValue.isNaN {
524-
let double = Double(exactly: number!)
525-
let expectedDouble = Double(exactly: interestingValue)
526-
testDouble(expectedDouble, double)
527-
}
489+
490+
let double = Double(exactly: number!)
491+
let expectedDouble = Double(exactly: interestingValue)
492+
testDouble(expectedDouble, double)
528493
}
529494
let bridged = interestingValue._bridgeToObjectiveC()
530495
testNumber(bridged)
@@ -558,16 +523,13 @@ class TestNSNumberBridging : XCTestCase {
558523
let uint = UInt(exactly: number!)
559524
XCTAssertEqual(UInt(exactly: interestingValue), uint)
560525

561-
let float = Float(truncating: number!)
562-
let expectedFloat = Float(reasonably: interestingValue)
526+
let float = Float(exactly: number!)
527+
let expectedFloat = Float(exactly: interestingValue)
563528
testFloat(expectedFloat, float)
564-
565-
// FIXME: Double.nan doesn't round-trip through NSNumber
566-
if !interestingValue.isNaN {
567-
let double = Double(exactly: number!)
568-
let expectedDouble = Double(exactly: interestingValue)
569-
testDouble(expectedDouble, double)
570-
}
529+
530+
let double = Double(exactly: number!)
531+
let expectedDouble = Double(exactly: interestingValue)
532+
testDouble(expectedDouble, double)
571533
}
572534
let bridged = interestingValue._bridgeToObjectiveC()
573535
testNumber(bridged)

0 commit comments

Comments
 (0)