Skip to content

Commit

Permalink
Merge pull request #14 from jackymelb/swift4.0
Browse files Browse the repository at this point in the history
Remove ArithmeticOverflow type usages and change FloatingPoint to BinaryFloatingPoint due to Swift 4.0 API changes.
  • Loading branch information
Jitsusama authored Sep 7, 2017
2 parents 5b52563 + af2bf4b commit 7da627e
Show file tree
Hide file tree
Showing 2 changed files with 86 additions and 89 deletions.
105 changes: 53 additions & 52 deletions Sources/UInt128.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public struct UInt128 {
}

/// Undocumented private variable required for passing this type
/// to a FloatingPoint type. See FloatingPointTypes.swift.gyb in
/// to a BinaryFloatingPoint type. See FloatingPoint.swift.gyb in
/// the Swift stdlib/public/core directory.
internal var signBitIndex: Int {
return 127 - leadingZeroBitCount
Expand Down Expand Up @@ -193,44 +193,40 @@ extension UInt128 : FixedWidthInteger {

// MARK: Instance Methods

public func addingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: ArithmeticOverflow) {
var resultOverflow = ArithmeticOverflow.none
public func addingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) {
var resultOverflow = false
let (lowerBits, lowerOverflow) = self.value.lowerBits.addingReportingOverflow(rhs.value.lowerBits)
var (upperBits, upperOverflow) = self.value.upperBits.addingReportingOverflow(rhs.value.upperBits)

// If the lower bits overflowed, we need to add 1 to upper bits.
if lowerOverflow == .overflow {
if lowerOverflow {
(upperBits, resultOverflow) = upperBits.addingReportingOverflow(1)
}

let hasOverflowed = (upperOverflow == .overflow) || (resultOverflow == .overflow)

return (partialValue: UInt128(upperBits: upperBits, lowerBits: lowerBits),
overflow: ArithmeticOverflow(hasOverflowed))
overflow: upperOverflow || resultOverflow)
}

public func subtractingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: ArithmeticOverflow) {
var resultOverflow = ArithmeticOverflow.none
public func subtractingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) {
var resultOverflow = false
let (lowerBits, lowerOverflow) = self.value.lowerBits.subtractingReportingOverflow(rhs.value.lowerBits)
var (upperBits, upperOverflow) = self.value.upperBits.subtractingReportingOverflow(rhs.value.upperBits)

// If the lower bits overflowed, we need to subtract (borrow) 1 from the upper bits.
if lowerOverflow == .overflow {
if lowerOverflow {
(upperBits, resultOverflow) = upperBits.subtractingReportingOverflow(1)
}

let hasOverflowed = (upperOverflow == .overflow) || (resultOverflow == .overflow)


return (partialValue: UInt128(upperBits: upperBits, lowerBits: lowerBits),
overflow: ArithmeticOverflow(hasOverflowed))
overflow: upperOverflow || resultOverflow)
}

public func multipliedReportingOverflow(by rhs: UInt128) -> (partialValue: UInt128, overflow: ArithmeticOverflow) {
public func multipliedReportingOverflow(by rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) {
let multiplicationResult = self.multipliedFullWidth(by: rhs)
let overflowEncountered = multiplicationResult.high > 0

return (partialValue: multiplicationResult.low,
overflow: ArithmeticOverflow(overflowEncountered))
overflow: overflowEncountered)
}

public func multipliedFullWidth(by other: UInt128) -> (high: UInt128, low: UInt128.Magnitude) {
Expand Down Expand Up @@ -345,7 +341,7 @@ extension UInt128 : FixedWidthInteger {

addends.forEach { addend in
let interimSum = sum.addingReportingOverflow(addend)
if interimSum.overflow == .overflow {
if interimSum.overflow {
overflowCount += 1
}
sum = interimSum.partialValue
Expand All @@ -354,26 +350,26 @@ extension UInt128 : FixedWidthInteger {
return (truncatedValue: sum, overflowCount: overflowCount)
}

public func dividedReportingOverflow(by rhs: UInt128) -> (partialValue: UInt128, overflow: ArithmeticOverflow) {
public func dividedReportingOverflow(by rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) {
guard rhs != 0 else {
return (self, ArithmeticOverflow(true))
return (self, true)
}

let quotient = self.quotientAndRemainder(dividingBy: rhs).quotient
return (quotient, ArithmeticOverflow(false))
return (quotient, false)
}

public func dividingFullWidth(_ dividend: (high: UInt128, low: UInt128)) -> (quotient: UInt128, remainder: UInt128) {
return self._quotientAndRemainderFullWidth(dividingBy: dividend)
}

public func remainderReportingOverflow(dividingBy rhs: UInt128) -> (partialValue: UInt128, overflow: ArithmeticOverflow) {
public func remainderReportingOverflow(dividingBy rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) {
guard rhs != 0 else {
return (self, ArithmeticOverflow(true))
return (self, true)
}

let remainder = self.quotientAndRemainder(dividingBy: rhs).remainder
return (remainder, ArithmeticOverflow(false))
return (remainder, false)
}

public func quotientAndRemainder(dividingBy rhs: UInt128) -> (quotient: UInt128, remainder: UInt128) {
Expand Down Expand Up @@ -440,7 +436,33 @@ extension UInt128 : BinaryInteger {
// MARK: Instance Properties

public static var bitWidth : Int { return 128 }



// MARK: Instance Methods

public var words: [UInt] {
guard self != UInt128.min else {
return []
}

var words: [UInt] = []

for currentWord in 0 ... self.bitWidth / UInt.bitWidth {
let shiftAmount: UInt64 = UInt64(UInt.bitWidth) * UInt64(currentWord)
let mask = UInt64(UInt.max)
var shifted = self

if shiftAmount > 0 {
shifted &>>= UInt128(upperBits: 0, lowerBits: shiftAmount)
}

let masked: UInt128 = shifted & UInt128(upperBits: 0, lowerBits: mask)

words.append(UInt(masked.value.lowerBits))
}
return words
}

public var trailingZeroBitCount: Int {
let mask: UInt128 = 1
var bitsToWalk = self
Expand All @@ -457,7 +479,7 @@ extension UInt128 : BinaryInteger {

// MARK: Initializers

public init?<T : FloatingPoint>(exactly source: T) {
public init?<T : BinaryFloatingPoint>(exactly source: T) {
if source.isZero {
self = UInt128()
}
Expand All @@ -469,31 +491,10 @@ extension UInt128 : BinaryInteger {
}
}

public init<T : FloatingPoint>(_ source: T) {
public init<T : BinaryFloatingPoint>(_ source: T) {
self.init(UInt64(source))
}

// MARK: Instance Methods

/// Return the word at position `n` in self.
public func _word(at n: Int) -> UInt {
guard self != UInt128.min else {
return UInt()
}

let shiftAmount: UInt64 = UInt64(UInt.bitWidth) * UInt64(n)
let mask = UInt64(UInt.max)
var shifted = self

if shiftAmount > 0 {
shifted &>>= UInt128(upperBits: 0, lowerBits: shiftAmount)
}

let masked: UInt128 = shifted & UInt128(upperBits: 0, lowerBits: mask)

return UInt(masked.value.lowerBits)
}


// MARK: Type Methods

public static func /(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 {
Expand Down Expand Up @@ -622,7 +623,7 @@ extension UInt128 : Numeric {
}
public static func *(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 {
let result = lhs.multipliedReportingOverflow(by: rhs)
precondition(result.overflow != .overflow, "Multiplication overflow!")
precondition(!result.overflow, "Multiplication overflow!")
return result.partialValue
}
public static func *=(_ lhs: inout UInt128, _ rhs: UInt128) {
Expand Down Expand Up @@ -763,11 +764,11 @@ extension UInt128 {
}
}

// MARK: - FloatingPoint Interworking
// MARK: - BinaryFloatingPoint Interworking

extension FloatingPoint {
extension BinaryFloatingPoint {
public init(_ value: UInt128) {
precondition(value.value.upperBits == 0, "Value is too large to fit into a FloatingPoint until a 128bit FloatingPoint type is defined.")
precondition(value.value.upperBits == 0, "Value is too large to fit into a BinaryFloatingPoint until a 128bit BinaryFloatingPoint type is defined.")
self.init(value.value.lowerBits)
}

Expand Down
70 changes: 33 additions & 37 deletions Tests/UInt128Tests/UInt128Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,6 @@ class BaseTypeTests : XCTestCase {
}
}

let didOverflow = ArithmeticOverflow(true)
let didNotOverflow = ArithmeticOverflow(false)

class FixedWidthIntegerTests : XCTestCase {
func testNonzeroBitCount() {
var tests = [(input: UInt128.min, result: 0)]
Expand Down Expand Up @@ -231,19 +228,19 @@ class FixedWidthIntegerTests : XCTestCase {
func testAddingReportingOverflow() {
// 0 + 0 = 0
var tests = [(augend: UInt128.min, addend: UInt128.min,
sum: (partialValue: UInt128.min, overflow: didNotOverflow))]
sum: (partialValue: UInt128.min, overflow: false))]
// UInt128.max + 0 = UInt128.max
tests.append((augend: UInt128.max, addend: UInt128.min,
sum: (partialValue: UInt128.max, overflow: didNotOverflow)))
sum: (partialValue: UInt128.max, overflow: false)))
// UInt128.max + 1 = 0, with overflow
tests.append((augend: UInt128.max, addend: UInt128(1),
sum: (partialValue: UInt128.min, overflow: didOverflow)))
sum: (partialValue: UInt128.min, overflow: true)))
// UInt128.max + 2 = 1, with overflow
tests.append((augend: UInt128.max, addend: UInt128(2),
sum: (partialValue: UInt128(1), overflow: didOverflow)))
sum: (partialValue: UInt128(1), overflow: true)))
// UInt64.max + 1 = UInt64.max + 1
tests.append((augend: UInt128(UInt64.max), addend: UInt128(1),
sum: (partialValue: UInt128(upperBits: 1, lowerBits: 0), overflow: didNotOverflow)))
sum: (partialValue: UInt128(upperBits: 1, lowerBits: 0), overflow: false)))

tests.forEach { test in
let sum = test.augend.addingReportingOverflow(test.addend)
Expand All @@ -255,22 +252,22 @@ class FixedWidthIntegerTests : XCTestCase {
func testSubtractingReportingOverflow() {
// 0 - 0 = 0
var tests = [(minuend: UInt128.min, subtrahend: UInt128.min,
difference: (partialValue: UInt128.min, overflow: didNotOverflow))]
difference: (partialValue: UInt128.min, overflow: false))]
// Uint128.max - 0 = UInt128.max
tests.append((minuend: UInt128.max, subtrahend: UInt128.min,
difference: (partialValue: UInt128.max, overflow: didNotOverflow)))
difference: (partialValue: UInt128.max, overflow: false)))
// UInt128.max - 1 = UInt128.max - 1
tests.append((minuend: UInt128.max, subtrahend: UInt128(1),
difference: (partialValue: UInt128(upperBits: UInt64.max, lowerBits: (UInt64.max >> 1) << 1), overflow: didNotOverflow)))
difference: (partialValue: UInt128(upperBits: UInt64.max, lowerBits: (UInt64.max >> 1) << 1), overflow: false)))
// UInt64.max + 1 - 1 = UInt64.max
tests.append((minuend: UInt128(upperBits: 1, lowerBits: 0), subtrahend: UInt128(1),
difference: (partialValue: UInt128(UInt64.max), overflow: didNotOverflow)))
difference: (partialValue: UInt128(UInt64.max), overflow: false)))
// 0 - 1 = UInt128.max, with overflow
tests.append((minuend: UInt128.min, subtrahend: UInt128(1),
difference: (partialValue: UInt128.max, overflow: didOverflow)))
difference: (partialValue: UInt128.max, overflow: true)))
// 0 - 2 = UInt128.max - 1, with overflow
tests.append((minuend: UInt128.min, subtrahend: UInt128(2),
difference: (partialValue: (UInt128.max >> 1) << 1, overflow: didOverflow)))
difference: (partialValue: (UInt128.max >> 1) << 1, overflow: true)))

tests.forEach { test in
let difference = test.minuend.subtractingReportingOverflow(test.subtrahend)
Expand All @@ -282,22 +279,22 @@ class FixedWidthIntegerTests : XCTestCase {
func testMultipliedReportingOverflow() {
// 0 * 0 = 0
var tests = [(multiplier: UInt128.min, multiplicator: UInt128.min,
product: (partialValue: UInt128.min, overflow: didNotOverflow))]
product: (partialValue: UInt128.min, overflow: false))]
// UInt64.max * UInt64.max = UInt128.max - UInt64.max - 1
tests.append((multiplier: UInt128(UInt64.max), multiplicator: UInt128(UInt64.max),
product: (partialValue: UInt128(upperBits: (UInt64.max >> 1) << 1, lowerBits: 1), overflow: didNotOverflow)))
product: (partialValue: UInt128(upperBits: (UInt64.max >> 1) << 1, lowerBits: 1), overflow: false)))
// UInt128.max * 0 = 0
tests.append((multiplier: UInt128.max, multiplicator: UInt128.min,
product: (partialValue: UInt128.min, overflow: didNotOverflow)))
product: (partialValue: UInt128.min, overflow: false)))
// UInt128.max * 1 = UInt128.max
tests.append((multiplier: UInt128.max, multiplicator: UInt128(1),
product: (partialValue: UInt128.max, overflow: didNotOverflow)))
product: (partialValue: UInt128.max, overflow: false)))
// UInt128.max * 2 = UInt128.max - 1, with overflow
tests.append((multiplier: UInt128.max, multiplicator: UInt128(2),
product: (partialValue: (UInt128.max >> 1) << 1, overflow: didOverflow)))
product: (partialValue: (UInt128.max >> 1) << 1, overflow: true)))
// UInt128.max * UInt128.max = 1, with overflow
tests.append((multiplier: UInt128.max, multiplicator: UInt128.max,
product: (partialValue: UInt128(1), overflow: didOverflow)))
product: (partialValue: UInt128(1), overflow: true)))

tests.forEach { test in
let product = test.multiplier.multipliedReportingOverflow(by: test.multiplicator)
Expand Down Expand Up @@ -327,35 +324,35 @@ class FixedWidthIntegerTests : XCTestCase {
}
}

func divisionTests() -> [(dividend: UInt128, divisor: UInt128, quotient: (partialValue: UInt128, overflow: ArithmeticOverflow), remainder: (partialValue: UInt128, overflow: ArithmeticOverflow))] {
func divisionTests() -> [(dividend: UInt128, divisor: UInt128, quotient: (partialValue: UInt128, overflow: Bool), remainder: (partialValue: UInt128, overflow: Bool))] {
// 0 / 0 = 0, remainder 0, with overflow
var tests = [(dividend: UInt128.min, divisor: UInt128.min,
quotient: (partialValue: UInt128.min, overflow: didOverflow),
remainder: (partialValue: UInt128.min, overflow: didOverflow))]
quotient: (partialValue: UInt128.min, overflow: true),
remainder: (partialValue: UInt128.min, overflow: true))]
// 0 / 1 = 0, remainder 0
tests.append((dividend: UInt128.min, divisor: UInt128(1),
quotient: (partialValue: UInt128.min, overflow: didNotOverflow),
remainder: (partialValue: UInt128.min, overflow: didNotOverflow)))
quotient: (partialValue: UInt128.min, overflow: false),
remainder: (partialValue: UInt128.min, overflow: false)))
// 0 / UInt128.max = 0, remainder 0
tests.append((dividend: UInt128.min, divisor: UInt128.max,
quotient: (partialValue: UInt128.min, overflow: didNotOverflow),
remainder: (partialValue: UInt128.min, overflow: didNotOverflow)))
quotient: (partialValue: UInt128.min, overflow: false),
remainder: (partialValue: UInt128.min, overflow: false)))
// 1 / 0 = 1, remainder 1, with overflow
tests.append((dividend: UInt128(1), divisor: UInt128.min,
quotient: (partialValue: UInt128(1), overflow: didOverflow),
remainder: (partialValue: UInt128(1), overflow: didOverflow)))
quotient: (partialValue: UInt128(1), overflow: true),
remainder: (partialValue: UInt128(1), overflow: true)))
// UInt128.max / UInt64.max = UInt128(upperBits: 1, lowerBits: 1), remainder 0
tests.append((dividend: UInt128.max, divisor: UInt128(UInt64.max),
quotient: (partialValue: UInt128(upperBits: 1, lowerBits: 1), overflow: didNotOverflow),
remainder: (partialValue: UInt128.min, overflow: didNotOverflow)))
quotient: (partialValue: UInt128(upperBits: 1, lowerBits: 1), overflow: false),
remainder: (partialValue: UInt128.min, overflow: false)))
// UInt128.max / UInt128.max = 1, remainder 0
tests.append((dividend: UInt128.max, divisor: UInt128.max,
quotient: (partialValue: UInt128(1), overflow: didNotOverflow),
remainder: (partialValue: UInt128.min, overflow: didNotOverflow)))
quotient: (partialValue: UInt128(1), overflow: false),
remainder: (partialValue: UInt128.min, overflow: false)))
// UInt64.max / UInt128.max = 0, remainder UInt64.max
tests.append((dividend: UInt128(UInt64.max), divisor: UInt128.max,
quotient: (partialValue: UInt128.min, overflow: didNotOverflow),
remainder: (partialValue: UInt128(UInt64.max), overflow: didNotOverflow)))
quotient: (partialValue: UInt128.min, overflow: false),
remainder: (partialValue: UInt128(UInt64.max), overflow: false)))
return tests
}

Expand Down Expand Up @@ -496,8 +493,7 @@ class BinaryIntegerTests : XCTestCase {
let upperBits = UInt64("100000000000000000000000000000001", radix: 2)!
let testResult = UInt128(upperBits: upperBits, lowerBits: lowerBits)

for index in 0 ... UInt128.bitWidth / UInt.bitWidth {
let currentWord = testResult._word(at: index)
testResult.words.forEach { (currentWord) in
if UInt.bitWidth == 64 {
XCTAssertEqual(currentWord, 4294967297)
}
Expand Down

0 comments on commit 7da627e

Please sign in to comment.