Skip to content

Commit 514c9e9

Browse files
authored
Merge pull request #2837 from spevans/pr_nsnumber_equality
NSDecimalNumber: Fix comparison with NSNumber
2 parents 60fb698 + daa2438 commit 514c9e9

File tree

3 files changed

+44
-6
lines changed

3 files changed

+44
-6
lines changed

Sources/Foundation/NSDecimalNumber.swift

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -324,13 +324,14 @@ open class NSDecimalNumber : NSNumber {
324324
NSDecimalRound(&result, &input, Int(scale), roundingMode)
325325
return NSDecimalNumber(decimal: result)
326326
}
327-
327+
328328
// compare two NSDecimalNumbers
329329
open override func compare(_ decimalNumber: NSNumber) -> ComparisonResult {
330330
if let num = decimalNumber as? NSDecimalNumber {
331-
return decimal.compare(to:num.decimal)
331+
return decimal.compare(to: num.decimal)
332332
} else {
333-
return decimal.compare(to:Decimal(decimalNumber.doubleValue))
333+
// NOTE: The lhs must be an NSNumber and not self (an NSDecimalNumber) so that NSNumber.compare() is used
334+
return decimalNumber.compare(self)
334335
}
335336
}
336337

@@ -402,8 +403,14 @@ open class NSDecimalNumber : NSNumber {
402403
}
403404

404405
open override func isEqual(_ value: Any?) -> Bool {
405-
guard let other = value as? NSDecimalNumber else { return false }
406-
return self.decimal == other.decimal
406+
if let other = value as? NSDecimalNumber {
407+
return self.decimal == other.decimal
408+
}
409+
if let other = value as? NSNumber {
410+
// NOTE: The lhs must be an NSNumber and not self (an NSDecimalNumber) so that NSNumber.compare() is used
411+
return other.compare(self) == .orderedSame
412+
}
413+
return false
407414
}
408415

409416
override var _swiftValueOfOptimalType: Any {

Sources/Foundation/NSNumber.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ open class NSNumber : NSValue {
590590
open override var hash: Int {
591591
return Int(bitPattern: CFHash(_cfObject))
592592
}
593-
593+
594594
open override func isEqual(_ value: Any?) -> Bool {
595595
// IMPORTANT:
596596
// .isEqual() is invoked by the bridging machinery that gets triggered whenever you use '(-a NSNumber value-) as{,?,!} Int', so using a refutable pattern ('case let other as NSNumber') below will cause an infinite loop if value is an Int, and similarly for other types we can bridge to.
@@ -962,6 +962,10 @@ open class NSNumber : NSValue {
962962
}
963963
}
964964

965+
open func isEqual(to number: NSNumber) -> Bool {
966+
return compare(number) == .orderedSame
967+
}
968+
965969
open func description(withLocale locale: Locale?) -> String {
966970
guard let locale = locale else { return self.description }
967971
switch _CFNumberGetType2(_cfObject) {

Tests/Foundation/Tests/TestDecimal.swift

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,32 @@ class TestDecimal: XCTestCase {
12541254
XCTAssertEqual(d8?._length, 1)
12551255
}
12561256

1257+
func test_NSNumberEquality() {
1258+
1259+
let values = [
1260+
(NSNumber(value: Int.min), NSDecimalNumber(decimal: Decimal(Int.min))),
1261+
(NSNumber(value: Int.max), NSDecimalNumber(decimal: Decimal(Int.max))),
1262+
(NSNumber(value: Double(1.1)), NSDecimalNumber(decimal: Decimal(Double(1.1)))),
1263+
(NSNumber(value: Float(-1.0)), NSDecimalNumber(decimal: Decimal(-1))),
1264+
(NSNumber(value: Int8(1)), NSDecimalNumber(decimal: Decimal(1))),
1265+
(NSNumber(value: UInt8.max), NSDecimalNumber(decimal: Decimal(255))),
1266+
(NSNumber(value: Int16.min), NSDecimalNumber(decimal: Decimal(-32768))),
1267+
]
1268+
1269+
for pair in values {
1270+
let number = pair.0
1271+
let decimalNumber = pair.1
1272+
1273+
XCTAssertEqual(number.compare(decimalNumber), .orderedSame)
1274+
XCTAssertTrue(number.isEqual(to: decimalNumber))
1275+
XCTAssertEqual(number, decimalNumber)
1276+
1277+
XCTAssertEqual(decimalNumber.compare(number), .orderedSame)
1278+
XCTAssertTrue(decimalNumber.isEqual(to: number))
1279+
XCTAssertEqual(decimalNumber, number)
1280+
}
1281+
}
1282+
12571283
static var allTests : [(String, (TestDecimal) -> () throws -> Void)] {
12581284
return [
12591285
("test_NSDecimalNumberInit", test_NSDecimalNumberInit),
@@ -1283,6 +1309,7 @@ class TestDecimal: XCTestCase {
12831309
("test_NSDecimalString", test_NSDecimalString),
12841310
("test_multiplyingByPowerOf10", test_multiplyingByPowerOf10),
12851311
("test_initExactly", test_initExactly),
1312+
("test_NSNumberEquality", test_NSNumberEquality),
12861313
]
12871314
}
12881315
}

0 commit comments

Comments
 (0)