@@ -1658,39 +1658,32 @@ extension BinaryInteger {
1658
1658
public static func == <
1659
1659
Other: BinaryInteger
1660
1660
> ( lhs: Self , rhs: Other ) -> Bool {
1661
- let lhsNegative = Self . isSigned && lhs < ( 0 as Self )
1662
- let rhsNegative = Other . isSigned && rhs < ( 0 as Other )
1663
-
1664
- if lhsNegative != rhsNegative { return false }
1665
-
1666
- // Here we know the values are of the same sign.
1661
+ let rhs_ = Self ( truncatingIfNeeded: rhs)
1662
+ // Is `rhs` representable as a value of `Self` type? In other words, does
1663
+ // the bit pattern conversion above preserve the value of `rhs`?
1667
1664
//
1668
- // There are a few possible scenarios from here:
1669
- //
1670
- // 1. Both values are negative
1671
- // - If one value is strictly wider than the other, then it is safe to
1672
- // convert to the wider type.
1673
- // - If the values are of the same width, it does not matter which type we
1674
- // choose to convert to as the values are already negative, and thus
1675
- // include the sign bit if two's complement representation already.
1676
- // 2. Both values are non-negative
1677
- // - If one value is strictly wider than the other, then it is safe to
1678
- // convert to the wider type.
1679
- // - If the values are of the same width, than signedness matters, as not
1680
- // unsigned types are 'wider' in a sense they don't need to 'waste' the
1681
- // sign bit. Therefore it is safe to convert to the unsigned type.
1682
-
1683
- if lhs. bitWidth < rhs. bitWidth {
1684
- return Other ( truncatingIfNeeded: lhs) == rhs
1685
- }
1686
- if lhs. bitWidth > rhs. bitWidth {
1687
- return lhs == Self ( truncatingIfNeeded: rhs)
1665
+ // To find out the answer, we see if the value roundtrips by bit pattern
1666
+ // conversion back to `Self` [1], and we also check that the original bit
1667
+ // pattern conversion doesn't change the sign [2].
1668
+ if Other ( truncatingIfNeeded: rhs_) == rhs /* [1] */
1669
+ && ( rhs < ( 0 as Other ) ) == ( rhs_ < ( 0 as Self ) ) /* [2] */ {
1670
+ return lhs == rhs_
1688
1671
}
1689
1672
1690
- if Self . isSigned {
1691
- return Other ( truncatingIfNeeded: lhs) == rhs
1673
+ let lhs_ = Other ( truncatingIfNeeded: lhs)
1674
+ // Is `lhs` representable as a value of `Other` type?
1675
+ if Self ( truncatingIfNeeded: lhs_) == lhs
1676
+ && ( lhs < ( 0 as Self ) ) == ( lhs_ < ( 0 as Other ) ) {
1677
+ return lhs_ == rhs
1692
1678
}
1693
- return lhs == Self ( truncatingIfNeeded: rhs)
1679
+
1680
+ // If we're here, then either:
1681
+ // - `Self` is signed and fixed-width, `Other` is unsigned,
1682
+ // `lhs` is negative, and `rhs` is greater than `Self.max`; or
1683
+ // - `Other` is signed and fixed-width, `Self` is unsigned,
1684
+ // `rhs` is negative, and `lhs` is greater than `Other.max`.
1685
+ // Thus, `lhs != rhs`.
1686
+ return false
1694
1687
}
1695
1688
1696
1689
/// Returns a Boolean value indicating whether the two given values are not
@@ -1730,34 +1723,32 @@ extension BinaryInteger {
1730
1723
/// - rhs: Another integer to compare.
1731
1724
@_transparent
1732
1725
public static func < < Other: BinaryInteger > ( lhs: Self , rhs: Other ) -> Bool {
1733
- let lhsNegative = Self . isSigned && lhs < ( 0 as Self )
1734
- let rhsNegative = Other . isSigned && rhs < ( 0 as Other )
1735
- if lhsNegative != rhsNegative { return lhsNegative }
1736
-
1737
- if lhs == ( 0 as Self ) && rhs == ( 0 as Other ) { return false }
1738
-
1739
- // if we get here, lhs and rhs have the same sign. If they're negative,
1740
- // then Self and Other are both signed types, and one of them can represent
1741
- // values of the other type. Otherwise, lhs and rhs are positive, and one
1742
- // of Self, Other may be signed and the other unsigned.
1743
-
1744
- let rhsAsSelf = Self ( truncatingIfNeeded: rhs)
1745
- let rhsAsSelfNegative = rhsAsSelf < ( 0 as Self )
1746
-
1747
-
1748
- // Can we round-trip rhs through Other?
1749
- if Other ( truncatingIfNeeded: rhsAsSelf) == rhs &&
1750
- // This additional check covers the `Int8.max < (128 as UInt8)` case.
1751
- // Since the types are of the same width, init(truncatingIfNeeded:)
1752
- // will result in a simple bitcast, so that rhsAsSelf would be -128, and
1753
- // `lhs < rhsAsSelf` will return false.
1754
- // We basically guard against that bitcast by requiring rhs and rhsAsSelf
1755
- // to be the same sign.
1756
- rhsNegative == rhsAsSelfNegative {
1757
- return lhs < rhsAsSelf
1726
+ let rhs_ = Self ( truncatingIfNeeded: rhs)
1727
+ // Is `rhs` representable as a value of `Self` type? In other words, does
1728
+ // the bitcast operation above preserve the value of `rhs`?
1729
+ //
1730
+ // To find out the answer, we see if the value roundtrips by bitcasting back
1731
+ // to `Self` [1], and we also check that bitcasting doesn't change the sign
1732
+ // [2].
1733
+ if Other ( truncatingIfNeeded: rhs_) == rhs /* [1] */
1734
+ && ( rhs < ( 0 as Other ) ) == ( rhs_ < ( 0 as Self ) ) /* [2] */ {
1735
+ return lhs < rhs_
1736
+ }
1737
+
1738
+ let lhs_ = Other ( truncatingIfNeeded: lhs)
1739
+ // Is `lhs` representable as a value of `Other` type?
1740
+ if Self ( truncatingIfNeeded: lhs_) == lhs
1741
+ && ( lhs < ( 0 as Self ) ) == ( lhs_ < ( 0 as Other ) ) {
1742
+ return lhs_ < rhs
1758
1743
}
1759
1744
1760
- return Other ( truncatingIfNeeded: lhs) < rhs
1745
+ // If we're here, then either:
1746
+ // - `Self` is signed and fixed-width, `Other` is unsigned,
1747
+ // `lhs` is negative, and `rhs` is greater than `Self.max`; or
1748
+ // - `Other` is signed and fixed-width, `Self` is unsigned,
1749
+ // `rhs` is negative, and `lhs` is greater than `Other.max`.
1750
+ // Thus, `lhs < rhs` if and only if `Self.isSigned`.
1751
+ return Self . isSigned
1761
1752
}
1762
1753
1763
1754
/// Returns a Boolean value indicating whether the value of the first
0 commit comments