Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SE-0225] Implementation of isMultiple for BinaryInteger. #18689

Merged
merged 2 commits into from Sep 4, 2018
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -110,6 +110,10 @@ extension MockBinaryInteger : BinaryInteger {
var trailingZeroBitCount: Int {
return _value.trailingZeroBitCount
}

func isMultiple(of other: MockBinaryInteger<T>) -> Bool {
return _value.isMultiple(of: other._value)
}

static func + (
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
@@ -1151,6 +1151,21 @@ public protocol BinaryInteger :
func quotientAndRemainder(dividingBy rhs: Self)
-> (quotient: Self, remainder: Self)

/// Returns true if this value is a multiple of `other`, and false otherwise.
///
/// For two integers a and b, a is a multiple of b if there exists a third
/// integer q such that a = q*b. For example, 6 is a multiple of 3, because
/// 6 = 2*3, and zero is a multiple of everything, because 0 = 0*x, for any
/// integer x.
///
/// Two edge cases are worth particular attention:
/// - `x.isMultiple(of: 0)` is `true` if `x` is zero and `false` otherwise.
/// - `T.min.isMultiple(of: -1)` is `true` for signed integer `T`, even
/// though the quotient `T.min / -1` is not representable in type `T`.
///
/// - Parameter other: the value to test.
func isMultiple(of other: Self) -> Bool

/// Returns `-1` if this value is negative and `1` if it's positive;
/// otherwise, `0`.
///
@@ -2755,6 +2770,16 @@ extension FixedWidthInteger {
lhs = _nonMaskingRightShift(lhs, shift)
}

@inlinable
public func isMultiple(of other: Self) -> Bool {
// Nothing but zero is a multiple of zero.
if other == 0 { return self == 0 }
// Special case to avoid overflow on .min / -1 for signed types.
if Self.isSigned && other == -1 { return true }
// Having handled those special cases, this is safe.
return self % other == 0
}

@inlinable // FIXME(sil-serialize-all)
@inline(__always)
public static func _nonMaskingRightShift(_ lhs: Self, _ rhs: Int) -> Self {
@@ -23,9 +23,8 @@ func test8(_: ((Int, Int)) -> Int) {}
test8 { (_, _) -> Int in 2 }
test8 { (x, y) in x }

func isEven(_ x: Int) -> Bool { return x % 2 == 0 }
let items = Array(zip(0..<10, 0..<10))
_ = items.filter { (_, x) in isEven(x) }
_ = items.filter { (_, x) in x.isMultiple(of: 2) }
_ = items.filter { _ in true }

func toString(indexes: Int?...) -> String {
@@ -729,6 +729,11 @@ public struct _BigInt<Word: FixedWidthInteger & UnsignedInteger> :
let r = x._internalDivide(by: rhs)
return (x, r)
}

public func isMultiple(of other: _BigInt) -> Bool {
if other == 0 { return self == 0 }
return self % other == 0
}

public static func &=(lhs: inout _BigInt, rhs: _BigInt) {
var lhsTemp = lhs._dataAsTwosComplement()
@@ -1867,3 +1872,9 @@ BigIntBitTests.test("words") {
}

runAllTests()

BigIntTests.test("isMultiple") {
// Test that these do not crash.
expectTrue((0 as _BigInt<UInt>).isMultiple(of: 0))
expectFalse((1 as _BigInt<UInt>).isMultiple(of: 0))
}
@@ -39,8 +39,7 @@ import StdlibUnittest
/// integer type. Nesting `DoubleWidth` instances, in particular, may result in
/// undesirable performance.
public struct DoubleWidth<Base : FixedWidthInteger>
where Base.Magnitude : UnsignedInteger,
Base.Words : Collection, Base.Magnitude.Words : Collection {
where Base.Words : Collection, Base.Magnitude.Words : Collection {

This comment has been minimized.

Copy link
@stephentyrone

stephentyrone Aug 14, 2018

Author Member

An unrelated PR a few weeks ago removed the need for the .Magnitude : UnsignedInteger conformance. Removing it to get rid of warning in tests.


public typealias High = Base
public typealias Low = Base.Magnitude
@@ -282,7 +281,7 @@ extension DoubleWidth.Words: Collection {

public func index(after i: Index) -> Index {
switch i._value {
case let .low(li) where Base.bitWidth < UInt.bitWidth:
case .low where Base.bitWidth < UInt.bitWidth:

This comment has been minimized.

Copy link
@stephentyrone

stephentyrone Aug 14, 2018

Author Member

This change is also just cleaning up some noise.

return Index(.high(_high.endIndex))
case let .low(li):
let next = _low.index(after: li)
@@ -1004,6 +1003,19 @@ dwTests.test("DivideMinByMinusOne") {
_ = f(Int1024.min)
}

dwTests.test("isMultiple") {
func isMultipleTest<T: FixedWidthInteger>(type: T.Type) {
expectTrue(T.min.isMultiple(of: 2))
expectFalse(T.max.isMultiple(of: 10))
// Test that these do not crash.
expectTrue((0 as T).isMultiple(of: 0))
expectFalse((1 as T).isMultiple(of: 0))
expectTrue(T.min.isMultiple(of: 0 &- 1))
}
isMultipleTest(type: Int128.self)
isMultipleTest(type: UInt128.self)
}

dwTests.test("MultiplyMinByMinusOne") {
func f(_ x: Int1024) -> Int1024 {
return x * -1
@@ -148,6 +148,10 @@ extension MockBinaryInteger : BinaryInteger {
return _value.trailingZeroBitCount
}

func isMultiple(of other: MockBinaryInteger<T>) -> Bool {
return _value.isMultiple(of: other._value)
}

static func + (
lhs: MockBinaryInteger<T>, rhs: MockBinaryInteger<T>
) -> MockBinaryInteger<T> {
@@ -560,7 +564,7 @@ tests.test("truncatingIfNeeded") {

tests.test("Parsing/LosslessStringConvertible") {
func _toArray<T: LosslessStringConvertible>(_ text: String) -> [T] {
return text.split(separator: " ").map { T(String($0)) }.flatMap { $0 }
return text.split(separator: " ").map { T(String($0)) }.compactMap { $0 }

This comment has been minimized.

Copy link
@stephentyrone

stephentyrone Aug 14, 2018

Author Member

Minor update to silence warning while we're here.

}

expectEqualSequence([1, 2, 3], _toArray("1 2 3") as [Int])
@@ -798,6 +802,27 @@ tests.test("DivideMinByMinusOne") {
_ = f(Int.min)
}

tests.test("isMultiple") {
func isMultipleTest<T: FixedWidthInteger>(type: T.Type) {
expectTrue(T.min.isMultiple(of: 2))
expectFalse(T.max.isMultiple(of: 10))
// Test that these do not crash.
expectTrue((0 as T).isMultiple(of: 0))
expectFalse((1 as T).isMultiple(of: 0))
expectTrue(T.min.isMultiple(of: 0 &- 1))
}
isMultipleTest(type: Int.self)
isMultipleTest(type: Int8.self)
isMultipleTest(type: Int16.self)
isMultipleTest(type: Int32.self)
isMultipleTest(type: Int64.self)
isMultipleTest(type: UInt.self)
isMultipleTest(type: UInt8.self)
isMultipleTest(type: UInt16.self)
isMultipleTest(type: UInt32.self)
isMultipleTest(type: UInt64.self)
}

tests.test("MultiplyMinByMinusOne") {
func f(_ x: Int) -> Int {
return x * -1
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.