diff --git a/.gitignore b/.gitignore index df36ef4..299bea2 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,8 @@ xcuserdata # Vi swap files *.swp -# SPM files +# Artifacts /.build /Packages +/Carthage diff --git a/Docs/Swift4_Protocol_Conformance.md b/Docs/Swift4_Protocol_Conformance.md new file mode 100644 index 0000000..77ce1e2 --- /dev/null +++ b/Docs/Swift4_Protocol_Conformance.md @@ -0,0 +1,401 @@ +# Protocol Conformance Map + +This document lists protocol conformance properites and methods that are required in +order to have a fully (mostly?) stdlib compatible UnsignedInteger type for Swift version +3.2/4.0. + +## Needs to be Implemented + +This section summarizes those properties and methods that are not automatically +generated by the protocols requiring them, or by other protocols in the protocol +inheritance chain. + +### FixedWidthInteger + +* `var nonzeroBitCount: Int { get }` +* `var leadingZeroBitCount: Int { get }` +* `var bigEndian: Self { get }` +* `var littleEndian: Self { get }` +* `var byteSwapped: Self { get }` + +* `init(_truncatingBits bits: UInt)` +* `init(bigEndian value: Self)` +* `init(littleEndian value: Self)` + +* `func addingReportingOverflow(_ rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +* `func subtractingReportingOverflow(_ rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +* `func multipliedReportingOverflow(by rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +* `func multipliedFullWidth(by other: Self) -> (high: Self, low: Self.Magnitude)` +* `func dividedReportingOverflow(by rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +* `func dividingFullWidth(_ dividend: (high: Self, low: Self.Magnitude)) -> (quotient: Self, remainder: Self)` +* `func remainderReportingOverflow(dividingBy rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` + +### BinaryInteger + +* `var bitWidth : Int { get }` +* `var trailingZeroBitCount: Int { get }` + +* `init?(exactly source: T)` +* `init(_ source: T)` + +* `func _word(at n: Int) -> UInt` + +* `static func /(_ lhs: Self, _ rhs: Self) -> Self` +* `static func /=(_ lhs: inout Self, _ rhs: Self)` +* `static func %(_ lhs: Self, _ rhs: Self) -> Self` +* `static func %=(_ lhs: inout Self, _ rhs: Self)` +* `static func &=(_ lhs: inout Self, _ rhs: Self)` +* `static func |=(_ lhs: inout Self, _ rhs: Self)` +* `static func ^=(_ lhs: inout Self, _ rhs: Self)` +* `static func &>>=(_ lhs: inout Self, _ rhs: Self)` +* `static func &<<=(_ lhs: inout Self, _ rhs: Self)` + +### Hashable + +* `var hashValue: Int { get }` + +### Numeric + +* `static func +(_ lhs: Self, _ rhs: Self) -> Self` +* `static func +=(_ lhs: inout Self, rhs: Self)` +* `static func -(_ lhs: Self, _ rhs: Self) -> Self` +* `static func -=(_ lhs: inout Self, rhs: Self)` +* `static func *(_ lhs: Self, _ rhs: Self) -> Self` +* `static func *=(_ lhs: inout Self, rhs: Self)` + +### Equatable + +* `static func == (lhs: Self, rhs: Self) -> Bool` + +### ExpressibleByIntegerLiteral + +* `init (integerLiteral value: IntegerLiteralType)` + +### CustomStringConvertible + +* `var description: String { get }` + +### Comparable + +* `static func < (lhs: Self, rhs: Self) -> Bool` + +### _ExpressibleByBuiltinIntegerLiteral + +* `init (_builtinIntegerLiteral value: _MaxBuiltinIntegerType)` + + +## Protocol Details + +This lists out details gathered when investigating the stdlib for protocols that an +`UnsignedInteger` type should support. This lists each protocol, documents inherited +protocols, properties/methods that need to be implemented, and ones that are +automatically included. + +### FixedWidthInteger + +Conforms to: `BinaryInteger` and `_BitwiseOperations`. + +Needs to be implemented: +`func addingReportingOverflow(_ rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +`func subtractingReportingOverflow(_ rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +`func multipliedReportingOverflow(by rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +`func dividedReportingOverflow(by rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +`func remainderReportingOverflow(dividingBy rhs: Self) -> (partialValue: Self, overflow: ArithmeticOverflow)` +`func multipliedFullWidth(by other: Self) -> (high: Self, low: Self.Magnitude)` +`func dividingFullWidth(_ dividend: (high: Self, low: Self.Magnitude)) -> (quotient: Self, remainder: Self)` +`init(_truncatingBits bits: UInt)` +`var nonzeroBitCount: Int { get }` +`var leadingZeroBitCount: Int { get }` +`init(bigEndian value: Self)` +`init(littleEndian value: Self)` +`var bigEndian: Self { get }` +`var littleEndian: Self { get }` +`var byteSwapped: Self { get }` + +Automatically implemented: +`static var max: Self { get }` by `UnsignedInteger` protocol. +`static var min: Self { get }` by `UnsignedInteger` protocol. + +Default implementations: +`static var allZeros: Self { return 0 }` for `_BitwiseOperations` protocol. +`var bitWidth: Int { return Self.bitWidth }` for `BinaryInteger` protocol. + +`static prefix func ~ (x: Self) -> Self` for `_BitwiseOperations` protocol. + Relies on `&- (lhs:Self, rhs: Self)` operator. + +`static func >> (lhs: Self, rhs: Other) -> Self` + Relies on `.bitWidth`, `.isSigned` property, `&>>` operator, + `init(extendingOrTruncating:)` initializer. + +`static func >>= (lhs: inout Self, rhs: Other)` + Relies on `.bitWidth`, `.isSigned` property, `&>>` operator, + `init(extendingOrTruncating:)` initializer. + +`static func << (lhs: Self, rhs: Other) -> Self` + Relies on `.bitWidth`, `.isSigned` property, `&>>` operator, + `init(extendingOrTruncating:)` initializer. + +`static func <<= (lhs: inout Self, rhs: Other)` + Relies on `.bitWidth`, `.isSigned` property, `&>>` operator, + `init(extendingOrTruncating:)` initializer. + +`init(clamping source: Other)` + Relies on `.min` and `.max` property, `init(extendingOrTruncating:)` initializer. + +`func unsafeAdding(_ other: Self) -> Self` + Relies on `addingReportingOverflow` method. + +`func unsafeSubtracting(_ other: Self) -> Self` + Relies on `subtractingReportingOverflow` method. + +`func unsafeMultiplied(by other: Self) -> Self` + Relies on `multipliedReportingOverflow` method. + +`func unsafeDivided(by other: Self) -> Self` + Relies on `dividedReportingOverflow` method. + +`init(extendingOrTruncating source: T)` + Relies on `.bitWidth` property, `init(_truncatingBits:)` initializer. + +`static var _highBitIndex: Self` + Relies on `.bitWidth` property, `init(_truncatingBits:)` initializer. + +`static func &+ (lhs: Self, rhs: Self) -> Self` + Relies on `addingReportingOverflow` method. + +`static func &- (lhs: Self, rhs: Self) -> Self` + Relies on `subtractingReportingOverflow` method. + +`static func &* (lhs: Self, rhs: Self) -> Self` + Relies on `multipliedReportingOverflow` method. + +#### _BitwiseOperations + +Automatically implemented: +`static func & (lhs: Self, rhs: Self) -> Self` by `BinaryInteger` protocol. +`static func | (lhs: Self, rhs: Self) -> Self` by `BinaryInteger` protocol. +`static func ^ (lhs: Self, rhs: Self) -> Self` by `BinaryInteger` protocol. +`static prefix func ~ (x: Self) -> Self` by `FixedWidthInteger` protocol. + +```swift +@available(swift, deprecated: 3.1, obsoleted: 4.0) +static var allZeros: Self { get } +``` +by `FixedWidthInteger` protocol. + +#### BinaryInteger + +Conforms to: `Hashable`, `Numeric`, `CustomStringConvertible` and `Strideable`. + +Needs to be implemented: +`init?(exactly source: T)` +`init(_ source: T)` +`func _word(at n: Int) -> UInt` +`var bitWidth : Int { get }` +`var trailingZeroBitCount: Int { get }` +`static func /(_ lhs: Self, _ rhs: Self) -> Self` +`static func /=(_ lhs: inout Self, _ rhs: Self)` +`static func %(_ lhs: Self, _ rhs: Self) -> Self` +`static func %=(_ lhs: inout Self, _ rhs: Self)` +`static func &=(_ lhs: inout Self, _ rhs: Self)` +`static func |=(_ lhs: inout Self, _ rhs: Self)` +`static func ^=(_ lhs: inout Self, _ rhs: Self)` +`static func &>>=(_ lhs: inout Self, _ rhs: Self)` +`static func &<<=(_ lhs: inout Self, _ rhs: Self)` + +Automatically implemented: +`static var isSigned: Bool { get }` by `UnsignedInteger` protocol. +`init(_ source: T)` by `UnsignedInteger` and `BinaryInteger` protocols. +`init(extendingOrTruncating source: T)` by `FixedWidthInteger` protocol. +`init(clamping source: T)` by `FixedWidthInteger` protocol. +`var words: Words { get }` - has default implementation. +`static prefix func ~ (_ x: Self) -> Self` by `FixedWidthInteger` protocol. +`static func &(_ lhs: Self, _ rhs: Self) -> Self` - has default implementation. +`static func |(_ lhs: Self, _ rhs: Self) -> Self` - has default implementation. +`static func ^(_ lhs: Self, _ rhs: Self) -> Self` - has default implementation. +`static func &>>(_ lhs: Self, _ rhs: Self) -> Self` - has default implementation. +`static func &<<(_ lhs: Self, _ rhs: Self) -> Self` - has default implementation. +`func quotientAndRemainder(dividingBy rhs: Self) -> (quotient: Self, remainder: Self)` - has default implementation. +`func signum() -> Self` - has default implementation. + +Duplicate from another protocol: +`static func +(_ lhs: Self, _ rhs: Self) -> Self` - duplicate from `Numeric` protocol. +`static func +=(_ lhs: inout Self, _ rhs: Self)` - duplicate from `Numeric` protocol. +`static func -(_ lhs: Self, _ rhs: Self) -> Self` - duplicate from `Numeric` protocol. +`static func -=(_ lhs: inout Self, _ rhs: Self)` - duplicate from `Numeric` protocol. +`static func *(_ lhs: Self, _ rhs: Self) -> Self` - duplicate from `Numeric` protocol. +`static func *=(_ lhs: inout Self, _ rhs: Self)` - duplicate from `Numeric` protocol. + +Default Implementations: +`public init()` + +`var countRepresentedWords: Int` + Relies on `.bitWidth` property. + +`var words: [UInt]` + Relies on `.countRepresentedWords` property and `_word(at:)` method. + +`func signum() -> Self` + Relies on `< (lhs: Self, rhs: Self)` and `> (lhs: Self, rhs: Self)` operators. + +`func quotientAndRemainder(dividingBy rhs: Self) -> (quotient: Self, remainder: Self)` + Relies on `/` and `%` operators. + +`func distance(to other: Self) -> Int` for `Strideable` protocol. + Relies on `-` operator. + +`func advanced(by n: Int) -> Self` for `Strideable` protocol. + Relies on `+=` operator and `init(exactly:)` initializer. + +`static func & (lhs: Self, rhs: Self) -> Self` + Relies on `&=` operator. + +`static func | (lhs: Self, rhs: Self) -> Self` + Relies on `+=` operator. + +`static func ^ (lhs: Self, rhs: Self) -> Self` + Relies on `^=` operator. + +`static func &>> (lhs: Self, rhs: Self) -> Self` + Relies on `&>>=` operator. + +`static func &<< (lhs: Self, rhs: Self) -> Self` + Relies on `&<<=` operator. + +`static func != (lhs: Self, rhs: Self) -> Bool` + Relies on `== (lhs: Self, rhs: Self)` operator. + +`static func <= (lhs: Self, rhs: Self) -> Bool` for `Comparable` protocol. + Relies on `< (lhs: Self, rhs: Self)` operator. + +`static func >= (lhs: Self, rhs: Self) -> Bool` for `Comparable` protocol. + Relies on `< (lhs: Self, rhs: Self)` operator. + +`static func > (lhs: Self, rhs: Self) -> Bool` for `Comparable` protocol. + Relies on `< (lhs: Self, rhs: Self)` operator. + +`static func &>> (lhs: Self, rhs: Other) -> Self` + Relies on `&>>` operator and `init(extendingOrTruncating:)` initializer. + +`static func &>>= (lhs: inout Self, rhs: Other)` + Relies on `&>>` operator. + +`static func &<< (lhs: Self, rhs: Other) -> Self` + Relies on `&<<` operator and `init(extendingOrTruncating:)` initializer. + +`static func &<<= (lhs: inout Self, rhs: Other)` + Relies on `&<<` operator. + +`static func == (lhs: Self, rhs: Other) -> Bool` for `Equatable` protocol. + Relies on `.isSigned` and `.bitWidth` properties, `<` and `!=` operators, `init(extendingOrTruncating: Other)` initializer and `func == (lhs: Self, rhs: Self)` method. + +`static func != (lhs: Self, rhs: Other) -> Bool` + +`static func < (lhs: Self, rhs: Other) -> Bool` + Relies on `.isSigned` property, `<` and `==` operators, `init(extendingOrTruncating: Other)` initializer. + +`static func <= (lhs: Self, rhs: Other) -> Bool` + Relies on `<` operator. + +`static func >= (lhs: Self, rhs: Other) -> Bool` + Relies on `<` operator. + +`static func > (lhs: Self, rhs: Other) -> Bool` + Relies on `<` operator. + +##### Hashable + +Conforms to: `Equatable`. + +Needs to be implemented: +`var hashValue: Int { get }` + +##### Numeric + +Conforms to: `Equatable` and `ExpressibleByIntegerLiteral`. + +Needs to be implemented: +`static func +(_ lhs: Self, _ rhs: Self) -> Self` +`static func +=(_ lhs: inout Self, rhs: Self)` +`static func -(_ lhs: Self, _ rhs: Self) -> Self` +`static func -=(_ lhs: inout Self, rhs: Self)` +`static func *(_ lhs: Self, _ rhs: Self) -> Self` +`static func *=(_ lhs: inout Self, rhs: Self)` + +Automatically implemented: +`init?(exactly source: T)` by `UnsignedInteger` protocol. +`var magnitude: Magnitude { get }` by `UnsignedInteger` protocol. + + +###### Equatable + +Needs to be implemented: +`static func == (lhs: Self, rhs: Self) -> Bool` + +Automatically implemented: +`static func != (lhs: Self, rhs: Self) -> Bool` + +###### ExpressibleByIntegerLiteral + +Needs to be implemented: +`init (integerLiteral value: IntegerLiteralType)` + +##### CustomStringConvertible + +Needs to be implemented: +`var description: String { get }` + +##### Strideable + +Conforms to: `Comparable` + +Should be automatically implemented: +`func distance (to other: Self) -> Stride` +`func advanced (by n: Stride) -> Self` + +Has default implementations of `Comparable`'s `<` operator and `Equatable`'s +`==` operator based on the `distance(to:)` method. + +###### Comparable + +Conforms to: `Equatable` + +Needs to be implemented: + +`static func < (lhs: Self, rhs: Self) -> Bool` + +The below all have default implementations that derive from the above: + +`static func <= (lhs: Self, rhs: Self) -> Bool` +`static func > (lhs: Self, rhs: Self) -> Bool` +`static func >= (lhs: Self, rhs: Self) -> Bool` + +### UnsignedInteger + +Default implementations: + +`var magnitude: Self { return self }` for `Numeric` protocol. + +`static var isSigned: Bool { return false }` for `BinaryInteger` protocol. + +`var description: String` - doesn't work for anything larger than `UInt64`. + +`init(_ source: T)` + Relies on `.bitWidth` and `.max` property, `init(extendingOrTruncating:)` initializer. + +`init?(exactly source: T)` + Relies on `.bitWidth` and `.max` property, `init(extendingOrTruncating:)` initializer. + +`static var max: Self` + Relies on `~ (lhs: Self, rhs: Self) -> Self` operator. + +`static var min: Self` + +### _ExpressibleByBuiltinIntegerLiteral + +Needs to be implemented: +`init (_builtinIntegerLiteral value: _MaxBuiltinIntegerType)` + +Not inside this protocol, but rather in Policy.swift: + + public typealias _MaxBuiltinIntegerType = Builtin.Int2048 diff --git a/Playground.playground/contents.xcplayground b/Playground.playground/contents.xcplayground index 76285aa..7c091a8 100644 --- a/Playground.playground/contents.xcplayground +++ b/Playground.playground/contents.xcplayground @@ -1,4 +1,4 @@ - + \ No newline at end of file diff --git a/Sources/UInt128.swift b/Sources/UInt128.swift index 6e276bf..01f907b 100644 --- a/Sources/UInt128.swift +++ b/Sources/UInt128.swift @@ -7,7 +7,7 @@ // UnsignedInteger protocol as well as standard functions supported // by Swift's native unsigned integer types. // -// Copyright 2016 Joel Gerber +// Copyright 2017 Joel Gerber // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -25,65 +25,119 @@ // MARK: Error Type /// An `ErrorType` for `UInt128` data types. It includes cases -/// for the 4 possible errors that can occur during string -/// conversion, and 1 impossible error to satisfy a default -/// case in a switch statement. +/// for errors that can occur during string +/// conversion. public enum UInt128Errors : Error { - /// Invalid character supplied in input string. - case invalidStringCharacter - /// Invalid radix given for conversion. - case invalidRadix - /// Cannot convert an empty string into a UInt128 value. - case emptyString - /// The unsigned integer representation of string exceeds - /// 128 bits. - case stringInputOverflow + /// Input cannot be converted to a UInt128 value. + case invalidString } -// MARK: Data Type +// MARK: - Data Type /// A 128-bit unsigned integer value type. -/// Storage is based upon a tuple of 2, 64-bit unsigned integers. +/// Storage is based upon a tuple of 2, 64-bit, unsigned integers. public struct UInt128 { - // MARK: Type Properties - /// The largest value a UInt128 can hold. - public static var max = UInt128(upperBits: .max, lowerBits: .max) - - /// The smallest value a UInt128 can hold. - public static var min = UInt128(upperBits: 0, lowerBits: 0) - - /// Returns size of data type in bits. - public static var _sizeInBits: Int32 = 128 - - /// Returns size of data type in bytes. - public static var _sizeInBytes: Int32 = 128 / 8 - // MARK: Instance Properties + /// Internal value is presented as a tuple of 2 64-bit /// unsigned integers. - internal var value: (upperBits: UInt64, lowerBits: UInt64) = (0, 0) + internal var value: (upperBits: UInt64, lowerBits: UInt64) /// Counts up the significant bits in stored data. public var significantBits: UInt128 { - // Will turn into final result. - var significantBitCount: UInt128 = 0 - // The bits to crawl in loop. - var bitsToWalk: UInt64 = 0 + var significantBits: UInt128 = 0 + var bitsToWalk: UInt64 = 0 // The bits to crawl in loop. + + // When upperBits > 0, lowerBits are all significant. if self.value.upperBits > 0 { bitsToWalk = self.value.upperBits - // When upperBits > 0, lowerBits are all significant. - significantBitCount += 64 + significantBits = 64 } else if self.value.lowerBits > 0 { bitsToWalk = self.value.lowerBits } + // Walk significant bits by shifting right until all bits are equal to 0. while bitsToWalk > 0 { bitsToWalk >>= 1 - significantBitCount += 1 + significantBits += 1 } - return significantBitCount + + return significantBits + } + + /// Undocumented private variable required for passing this type + /// to a BinaryFloatingPoint type. See FloatingPoint.swift.gyb in + /// the Swift stdlib/public/core directory. + internal var signBitIndex: Int { + return 127 - leadingZeroBitCount + } + + // MARK: Initializers + + /// Designated initializer for the UInt128 type. + public init(upperBits: UInt64, lowerBits: UInt64) { + value.upperBits = upperBits + value.lowerBits = lowerBits } + + public init() { + self.init(upperBits: 0, lowerBits: 0) + } + + public init(_ source: UInt128) { + self.init(upperBits: source.value.upperBits, + lowerBits: source.value.lowerBits) + } + + /// Initialize a UInt128 value from a string. + /// + /// - parameter source: the string that will be converted into a + /// UInt128 value. Defaults to being analyzed as a base10 number, + /// but can be prefixed with `0b` for base2, `0o` for base8 + /// or `0x` for base16. + public init(_ source: String) throws { + guard let result = UInt128._valueFromString(source) else { + throw UInt128Errors.invalidString + } + self = result + } +} + +// MARK: - FixedWidthInteger Conformance +extension UInt128 : FixedWidthInteger { + // MARK: Instance Properties + + public var nonzeroBitCount: Int { + var nonZeroCount = 0 + var shiftWidth = 0 + + while shiftWidth < 128 { + let shiftedSelf = self &>> shiftWidth + let currentBit = shiftedSelf & 1 + if currentBit == 1 { + nonZeroCount += 1 + } + shiftWidth += 1 + } + + return nonZeroCount + } + + public var leadingZeroBitCount: Int { + var zeroCount = 0 + var shiftWidth = 127 + + while shiftWidth >= 0 { + let currentBit = self &>> shiftWidth + guard currentBit == 0 else { break } + zeroCount += 1 + shiftWidth -= 1 + } + + return zeroCount + } + /// Returns the big-endian representation of the integer, changing the byte order if necessary. public var bigEndian: UInt128 { #if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) @@ -106,153 +160,17 @@ public struct UInt128 { public var byteSwapped: UInt128 { return UInt128(upperBits: self.value.lowerBits.byteSwapped, lowerBits: self.value.upperBits.byteSwapped) } - - // MARK: Type Methods - - /// Create a UInt128 instance from the supplied string. - /// - requires: - /// `string` must match the following patterns: - /// `/0x[0-9a-fA-F]+/` for hexadecimal, `/[0-9]+/` for decimal, - /// `/0o[0-7]+/` for octal or `/0b[01]+/` for binary. - /// - parameter string: - /// A string representation of a number in one of the supported - /// radix types (base 16, 10, 8 or 2). - /// - returns: - /// Returns a valid UInt128 instance. - /// - throws: - /// A `UInt128Errors` ErrorType. - internal static func fromUnparsedString(_ string: String) throws -> UInt128 { - // Empty string is bad. - guard !string.isEmpty else { - throw UInt128Errors.emptyString - } - // Internal variables. - let radix: UInt8 - var builtString = String() - // Determine radix based upon number prefix. - if string.hasPrefix("0b") { // binary - radix = 2 - } else if string.hasPrefix("0o") { // octal - radix = 8 - } else if string.hasPrefix("0x") { // hex - radix = 16 - } else { // default to decimal. - radix = 10 - } - // Used to hold passed string with radix removed. - var stringSansRadix = string - // Remove the radix identifier from the front of the string. - if radix != 10 { - stringSansRadix.removeSubrange(string.startIndex...string.characters.index(string.startIndex, offsetBy: 1)) - } - // Lowercase the string for normalization purposes. - stringSansRadix = stringSansRadix.lowercased() - // Filter string for valid digits and build into a new string. - for character in stringSansRadix.characters { - switch character { - case "0"..."1": // Digits specific to all numbering systems. - builtString.append(character) - case "2"..."7": // Digits specific to octal, decimal and hexadecimal. - guard radix == 8 || radix == 10 || radix == 16 else { - throw UInt128Errors.invalidStringCharacter - } - builtString.append(character) - case "8"..."9": // Digits specific to decimal and hexadecimal. - guard radix == 10 || radix == 16 else { - throw UInt128Errors.invalidStringCharacter - } - builtString.append(character) - case "a"..."f": // Digits specific to hexadecimal. - guard radix == 16 else { - throw UInt128Errors.invalidStringCharacter - } - builtString.append(character) - default: - throw UInt128Errors.invalidStringCharacter - } - } - // Remove any leading 0s. - for character in builtString.characters { - if character == "0" { - builtString.remove(at: builtString.startIndex) - } else { - break - } - } - // Pass parsed string to factory function. - return try fromParsedString(builtString.utf16, radix: radix) - } - - /// Returns a newly instantiated UInt128 type from a pre-parsed and safe string. - /// This should not be called directly, refer to `fromUnparsedString` for a proper - /// front-end method. - /// - requires: - /// `string` must match the pattern `/[0-9a-z]+/`. - /// - parameter string: - /// A string representation of a number in one of the supported - /// radix types (base 2-36). - /// - parameter radix: - /// The radix of the numbering system the `string` parameter - /// is encoded by. - /// - returns: - /// Returns a valid UInt128 instance. - /// - throws: - /// A `UInt128Errors` ErrorType. - internal static func fromParsedString(_ string: String.UTF16View, radix: UInt8) throws -> UInt128 { - var result: UInt128 = 0 - // Define ranges. Used to convert character value to numeric later. - let digit = "0".utf16.first!..."9".utf16.first! - let lower = "a".utf16.first!..."z".utf16.first! - // radix cannot exceed basic number and [a-z] character set count. - guard radix <= UInt8(digit.count + lower.count) else { - throw UInt128Errors.invalidRadix - } - // Loop through each charcter's CodeUnit value. - for character in string { - var current: UInt128 = 0 - // For each CodeUnit value, convert to a "decimal" value. - switch character { - case digit: current = UInt128(character - digit.lowerBound) - case lower: current = UInt128(character - lower.lowerBound) + 10 - default: throw UInt128Errors.invalidStringCharacter - } - // Make room for current positional value. - let (multiplyResult, multiplyOverflow) = multiplyWithOverflow(result, UInt128(radix)) - // Add current value to temporary result. - let (addResult, addOverflow) = addWithOverflow(multiplyResult, current) - // We don't desire handling overflows during string conversion. - guard !multiplyOverflow && !addOverflow else { - throw UInt128Errors.stringInputOverflow - } - result = addResult - } - return result - } - - // MARK: Initialization - - /// Designated initializer for the UInt128 type. - public init(upperBits: UInt64, lowerBits: UInt64) { - value.upperBits = upperBits - value.lowerBits = lowerBits - } - - public init() { - self.init(upperBits: 0, lowerBits: 0) - } - - public init(_ value: UInt128) { - self.value = value.value - } - - public init(_ value: Int) { - self.init(upperBits: 0, lowerBits: UInt64(value)) - } - - public init(_ value: String) throws { - try self = UInt128.fromUnparsedString(value) - } - + + // MARK: Initializers + + /// Creates a UInt128 from a given value, with the input's value + /// truncated to a size no larger than what UInt128 can handle. + /// Since the input is constrained to an UInt, no truncation needs + /// to occur, as a UInt is currently 64 bits at the maximum. + public init(_truncatingBits bits: UInt) { + self.init(upperBits: 0, lowerBits: UInt64(bits)) + } + /// Creates an integer from its big-endian representation, changing the /// byte order if necessary. public init(bigEndian value: UInt128) { @@ -262,7 +180,7 @@ public struct UInt128 { self = value #endif } - + /// Creates an integer from its little-endian representation, changing the /// byte order if necessary. public init(littleEndian value: UInt128) { @@ -272,628 +190,609 @@ public struct UInt128 { self = value.byteSwapped #endif } - + // MARK: Instance Methods - - /// Converts the stored value into a string representation. - /// - parameter radix: - /// The radix for the base numbering system you wish to have - /// the type presented in. - /// - parameter uppercase: - /// Determines whether letter components of the outputted string will be in - /// uppercase format or not. - /// - returns: - /// String representation of the stored UInt128 value. - internal func toString(radix: Int = 10, uppercase: Bool = true) -> String { - precondition(radix > 1 && radix < 17, "radix must be within the range of 2-16.") - // Will store the final string result. - var result = String() - // Simple case. - if self == 0 { - result.append("0") - return result - } - // Used as the check for indexing through UInt128 for string interpolation. - var divmodResult = (quotient: self, remainder: UInt128(0)) - // Will hold the pool of possible values. - let characterPool = (uppercase) ? "0123456789ABCDEF" : "0123456789abcdef" - // Go through internal value until every base position is string(ed). - repeat { - divmodResult = divmodResult.quotient /% UInt128(radix) - let index = characterPool.characters.index(characterPool.startIndex, offsetBy: Int(divmodResult.remainder)) - result.insert(characterPool[index], at: result.startIndex) - } while divmodResult.quotient > 0 - return result - } -} - -// MARK: - UnsignedInteger - -extension UInt128 : UnsignedInteger { - public init(_ value: UIntMax) { - self.init(upperBits: 0, lowerBits: UInt64(value)) - } - - public init(_ value: UInt) { - self.init(value.toUIntMax()) - } - - public init(_ value: UInt8) { - self.init(value.toUIntMax()) - } - - public init(_ value: UInt16) { - self.init(value.toUIntMax()) - } - - public init(_ value: UInt32) { - self.init(value.toUIntMax()) - } - - public func toUIntMax() -> UIntMax { - return value.lowerBits.toUIntMax() - } - - // MARK: Hashable Conformance - - public var hashValue: Int { - return self.value.lowerBits.hashValue ^ self.value.upperBits.hashValue - } - - // MARK: ForwardIndexType Conformance - - @available(*, deprecated) - public func successor() -> UInt128 { - return self &+ 1 - } - - // MARK: BidirectionalIndexType Conformance - - @available(*, deprecated) - public func predecessor() -> UInt128 { - return self &- 1 - } -} - -// MARK: - Strideable - -extension UInt128 : Strideable { - public typealias Stride = Int - - /// Returns an instance of UInt128 that is the current instance's - /// value increased by `n` when `n` is positive or decreased - /// by `n` when `n` is negative. - public func advanced(by n: Stride) -> UInt128 { - if n < 0 { - return self &- UInt128(n * -1) - } - return self &+ UInt128(n) - } - - /// Returns an instance of UInt128 that is the current instance's - /// value increased by `n` when `n` is positive or decreased - /// by `n` when `n` is negative. - @available(*, deprecated) - public func advancedBy(_ n: Stride) -> UInt128 { - return self.advanced(by: n) - } - - /// Returns the distance from the current UInt128 value to the supplied - /// UInt128 value. This implementation is limited since a signed Int128 - /// data type does not exist, so it has to fall back to an IntMax - /// representation which lacks half of the storage space when end - /// is less than the value of self. - public func distance(to other: UInt128) -> Int { - if other >= self { - return Stride(other - self) - } - return Stride(other) &- Stride(self) - } - - /// Returns the distance from the current UInt128 value to the supplied - /// UInt128 value. This implementation is limited since a signed Int128 - /// data type does not exist, so it has to fall back to an IntMax - /// representation which lacks half of the storage space when end - /// is less than the value of self. - @available(*, deprecated) - public func distanceTo(_ end: UInt128) -> Stride { - return self.distance(to: end) - } -} - -// MARK: - ExpressibleByIntegerLiteral - -extension UInt128 : ExpressibleByIntegerLiteral { - public init(integerLiteral value: IntegerLiteralType) { - self.init(value) - } - - public init(_builtinIntegerLiteral value: _MaxBuiltinIntegerType) { - self.init(UInt64(_builtinIntegerLiteral: value)) - } -} - -// MARK: - ExpressibleByStringLiteral - -extension UInt128 : ExpressibleByStringLiteral { - public init(stringLiteral value: StringLiteralType) { - self.init() - do { - try self = UInt128.fromUnparsedString(value) - } catch { return } - } - - // MARK: UnicodeScalarLiteralConvertible - - public typealias UnicodeScalarLiteralType = String - - public init(unicodeScalarLiteral value: UnicodeScalarLiteralType) { - self.init(stringLiteral: value) - } - - // MARK: ExtendedGraphemeClusterLiteralConvertible - - public typealias ExtendedGraphemeClusterLiteralType = String - - public init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) { - self.init(stringLiteral: value) - } -} - -// MARK: - BitwiseOperations - -extension UInt128 : BitwiseOperations { - public static var allZeros: UInt128 = 0 -} - -/// Performs a bitwise AND operation on 2 UInt128 data types. -public func &(lhs: UInt128, rhs: UInt128) -> UInt128 { - let upperBits = lhs.value.upperBits & rhs.value.upperBits - let lowerBits = lhs.value.lowerBits & rhs.value.lowerBits - return UInt128(upperBits: upperBits, lowerBits: lowerBits) -} - -public func &=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs & rhs -} - -/// Performs a bitwise OR operation on 2 UInt128 data types. -public func |(lhs: UInt128, rhs: UInt128) -> UInt128 { - let upperBits = lhs.value.upperBits | rhs.value.upperBits - let lowerBits = lhs.value.lowerBits | rhs.value.lowerBits - return UInt128(upperBits: upperBits, lowerBits: lowerBits) -} - -public func |=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs | rhs -} - -/// Performs a bitwise XOR operation on 2 UInt128 data types. -public func ^(lhs: UInt128, rhs: UInt128) -> UInt128 { - let upperBits = lhs.value.upperBits ^ rhs.value.upperBits - let lowerBits = lhs.value.lowerBits ^ rhs.value.lowerBits - return UInt128(upperBits: upperBits, lowerBits: lowerBits) -} - -public func ^=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs ^ rhs -} - -/// Performs bit inversion (complement) on the provided UInt128 data type -/// and returns the result. -prefix public func ~(rhs: UInt128) -> UInt128 { - let upperBits = ~rhs.value.upperBits - let lowerBits = ~rhs.value.lowerBits - return UInt128(upperBits: upperBits, lowerBits: lowerBits) -} - -/// Shifts `lhs`' bits left by `rhs` bits and returns the result. -public func <<(lhs: UInt128, rhs: UInt128) -> UInt128 { - if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 { - return 0 - } - switch rhs { - case 0: return lhs // Do nothing shift. - case 1...63: - let upperBits = (lhs.value.upperBits << rhs.value.lowerBits) + (lhs.value.lowerBits >> (64 - rhs.value.lowerBits)) - let lowerBits = lhs.value.lowerBits << rhs.value.lowerBits - return UInt128(upperBits: upperBits, lowerBits: lowerBits) - case 64: - // Shift 64 means move lower bits to upper bits. - return UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0) - case 65...127: - let upperBits = lhs.value.lowerBits << UInt64(rhs - 64) - return UInt128(upperBits: upperBits, lowerBits: 0) - default: return 0 - } -} - -public func <<=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs << rhs -} - -/// Shifts `lhs`' bits right by `rhs` bits and returns the result. -public func >>(lhs: UInt128, rhs: UInt128) -> UInt128 { - if rhs.value.upperBits > 0 || rhs.value.lowerBits > 128 { - return 0 - } - switch rhs { - case 0: return lhs // Do nothing shift. - case 1...63: - let upperBits = lhs.value.upperBits >> rhs.value.lowerBits - let lowerBits = (lhs.value.lowerBits >> rhs.value.lowerBits) + (lhs.value.upperBits << (64 - rhs.value.lowerBits)) - return UInt128(upperBits: upperBits, lowerBits: lowerBits) - case 64: - // Shift 64 means move upper bits to lower bits. - return UInt128(upperBits: 0, lowerBits: lhs.value.upperBits) - case 65...127: - let lowerBits = lhs.value.upperBits >> (rhs.value.lowerBits - 64) - return UInt128(upperBits: 0, lowerBits: lowerBits) - default: return 0 - } -} - -public func >>=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs >> rhs -} - -// MARK: IntegerArithmetic Conformance - -extension UInt128 : IntegerArithmetic { - public func toIntMax() -> IntMax { - precondition(self.value.lowerBits <= UInt64(IntMax.max) && self.value.upperBits == 0, "Converting `self` to 'IntMax' causes an integer overflow") - return IntMax(value.lowerBits) - } - - public static func addWithOverflow(_ lhs: UInt128, _ rhs: UInt128) -> (UInt128, overflow: Bool) { + + public func addingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) { var resultOverflow = false - // Add lower bits and check for overflow. - let (lowerBits, lowerOverflow) = UInt64.addWithOverflow( - lhs.value.lowerBits, rhs.value.lowerBits - ) - // Add upper bits and check for overflow. - var (upperBits, upperOverflow) = UInt64.addWithOverflow( - lhs.value.upperBits, rhs.value.upperBits - ) + 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 { - (upperBits, resultOverflow) = UInt64.addWithOverflow(upperBits, 1) + (upperBits, resultOverflow) = upperBits.addingReportingOverflow(1) } - return ( - UInt128(upperBits: upperBits, lowerBits: lowerBits), - upperOverflow || resultOverflow - ) + + return (partialValue: UInt128(upperBits: upperBits, lowerBits: lowerBits), + overflow: upperOverflow || resultOverflow) } - - public static func subtractWithOverflow(_ lhs: UInt128, _ rhs: UInt128) -> (UInt128, overflow: Bool) { + + public func subtractingReportingOverflow(_ rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) { var resultOverflow = false - // Subtract lower bits and check for overflow. - let (lowerBits, lowerOverflow) = UInt64.subtractWithOverflow( - lhs.value.lowerBits, rhs.value.lowerBits - ) - // Subtract upper bits and check for overflow. - var (upperBits, upperOverflow) = UInt64.subtractWithOverflow( - lhs.value.upperBits, rhs.value.upperBits - ) + 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 { - (upperBits, resultOverflow) = UInt64.subtractWithOverflow(upperBits, 1) + (upperBits, resultOverflow) = upperBits.subtractingReportingOverflow(1) } - return ( - UInt128(upperBits: upperBits, lowerBits: lowerBits), - upperOverflow || resultOverflow - ) - } - public static func divideWithOverflow(_ lhs: UInt128, _ rhs: UInt128) -> (UInt128, overflow: Bool) { - return ( - (lhs /% rhs).quotient, false - ) + return (partialValue: UInt128(upperBits: upperBits, lowerBits: lowerBits), + overflow: upperOverflow || resultOverflow) } - - public static func remainderWithOverflow(_ lhs: UInt128, _ rhs: UInt128) -> (UInt128, overflow: Bool) { - return ( - (lhs /% rhs).remainder, false - ) + + 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: overflowEncountered) } - - public static func multiplyWithOverflow(_ lhs: UInt128, _ rhs: UInt128) -> (UInt128, overflow: Bool) { - // Useful bitmasks to be used later. + + public func multipliedFullWidth(by other: UInt128) -> (high: UInt128, low: UInt128.Magnitude) { + // Bit mask that facilitates masking the lower 32 bits of a 64 bit UInt. let lower32 = UInt64(UInt32.max) - let upper32 = ~UInt64(UInt32.max) + // Decompose lhs into an array of 4, 32 significant bit UInt64s. let lhsArray = [ - lhs.value.upperBits >> 32, /*0*/ lhs.value.upperBits & lower32, /*1*/ - lhs.value.lowerBits >> 32, /*2*/ lhs.value.lowerBits & lower32 /*3*/ + self.value.upperBits >> 32, /*0*/ self.value.upperBits & lower32, /*1*/ + self.value.lowerBits >> 32, /*2*/ self.value.lowerBits & lower32 /*3*/ ] + // Decompose rhs into an array of 4, 32 significant bit UInt64s. let rhsArray = [ - rhs.value.upperBits >> 32, /*0*/ rhs.value.upperBits & lower32, /*1*/ - rhs.value.lowerBits >> 32, /*2*/ rhs.value.lowerBits & lower32 /*3*/ + other.value.upperBits >> 32, /*0*/ other.value.upperBits & lower32, /*1*/ + other.value.lowerBits >> 32, /*2*/ other.value.lowerBits & lower32 /*3*/ ] + // The future contents of this array will be used to store segment // multiplication results. var resultArray = [[UInt64]].init( - repeating: [UInt64].init( - repeating: 0, count: 4 - ), count: 4 + repeating: [UInt64].init(repeating: 0, count: 4), count: 4 ) - // Holds overflow status - var overflow = false + // Loop through every combination of lhsArray[x] * rhsArray[y] for rhsSegment in 0 ..< rhsArray.count { for lhsSegment in 0 ..< lhsArray.count { let currentValue = lhsArray[lhsSegment] * rhsArray[rhsSegment] - // Depending upon which segments we're looking at, we'll want to - // check for overflow conditions and flag them when encountered. - switch (lhsSegment, rhsSegment) { - case (0, 0...2): // lhsSegment 1 * rhsSegment 1 to 3 shouldn't have a value. - if currentValue > 0 { overflow = true } - case (0, 3): // lhsSegment 1 * rhsSegment 4 should only be 32 bits. - if currentValue >> 32 > 0 { overflow = true } - case (1, 0...1): // lhsSegment 2 * rhsSegment 1 or 2 shouldn't have a value. - if currentValue > 0 { overflow = true } - case (1, 2): // lhsSegment 2 * rhsSegment 3 should only be 32 bits. - if currentValue >> 32 > 0 { overflow = true } - case (2, 0): // lhsSegment 3 * rhsSegment 1 shouldn't have a value. - if currentValue > 0 { overflow = true } - case (2, 1): // lhsSegment 3 * rhsSegment 2 should only be 32 bits. - if currentValue >> 32 > 0 { overflow = true } - case (3, 0): // lhsSegment 4 * rhsSegment 1 should only be 32 bits. - if currentValue >> 32 > 0 { overflow = true } - default: break // only 1 overflow condition still exists which will be checked later. - } - // Save the current result into our two-dimensional result array. resultArray[lhsSegment][rhsSegment] = currentValue } } - // Perform multiplication similar to pen and paper, ignoring calculations - // that would definitely result in an overflow. - let fourthBitSegment = resultArray[3][3] & lower32 - var thirdBitSegment = resultArray[2][3] & lower32 + - resultArray[3][2] & lower32 - // Add overflow from 4th segment. - thirdBitSegment += (resultArray[3][3] & upper32) >> 32 - var secondBitSegment = resultArray[1][3] & lower32 + - resultArray[2][2] & lower32 + - resultArray[3][1] & lower32 - // Add overflows from 3rd segment. - secondBitSegment += (resultArray[2][3] & upper32) >> 32 - secondBitSegment += (resultArray[3][2] & upper32) >> 32 - var firstBitSegment = resultArray[0][3] & lower32 + - resultArray[1][2] & lower32 + - resultArray[2][1] & lower32 + - resultArray[3][0] & lower32 - // Add overflows from 2nd segment. - firstBitSegment += (resultArray[1][3] & upper32) >> 32 - firstBitSegment += (resultArray[2][2] & upper32) >> 32 - firstBitSegment += (resultArray[3][1] & upper32) >> 32 - // Slot the bit counts into the appropriate position with multiple adds. - return ( - UInt128(upperBits: firstBitSegment << 32, lowerBits: 0) &+ - UInt128(upperBits: secondBitSegment, lowerBits: 0) &+ - UInt128(upperBits: thirdBitSegment >> 32, lowerBits: thirdBitSegment << 32) &+ - UInt128(fourthBitSegment), - overflow || firstBitSegment >> 32 > 0 - ) + + // Perform multiplication similar to pen and paper in 64bit, 32bit masked increments. + let bitSegment8 = resultArray[3][3] & lower32 + let bitSegment7 = UInt128._variadicAdditionWithOverflowCount( + resultArray[2][3] & lower32, + resultArray[3][2] & lower32, + resultArray[3][3] >> 32) // overflow from bitSegment8 + let bitSegment6 = UInt128._variadicAdditionWithOverflowCount( + resultArray[1][3] & lower32, + resultArray[2][2] & lower32, + resultArray[3][1] & lower32, + resultArray[2][3] >> 32, // overflow from bitSegment7 + resultArray[3][2] >> 32, // overflow from bitSegment7 + bitSegment7.overflowCount) + let bitSegment5 = UInt128._variadicAdditionWithOverflowCount( + resultArray[0][3] & lower32, + resultArray[1][2] & lower32, + resultArray[2][1] & lower32, + resultArray[3][0] & lower32, + resultArray[1][3] >> 32, // overflow from bitSegment6 + resultArray[2][2] >> 32, // overflow from bitSegment6 + resultArray[3][1] >> 32, // overflow from bitSegment6 + bitSegment6.overflowCount) + let bitSegment4 = UInt128._variadicAdditionWithOverflowCount( + resultArray[0][2] & lower32, + resultArray[1][1] & lower32, + resultArray[2][0] & lower32, + resultArray[0][3] >> 32, // overflow from bitSegment5 + resultArray[1][2] >> 32, // overflow from bitSegment5 + resultArray[2][1] >> 32, // overflow from bitSegment5 + resultArray[3][0] >> 32, // overflow from bitSegment5 + bitSegment5.overflowCount) + let bitSegment3 = UInt128._variadicAdditionWithOverflowCount( + resultArray[0][1] & lower32, + resultArray[1][0] & lower32, + resultArray[0][2] >> 32, // overflow from bitSegment4 + resultArray[1][1] >> 32, // overflow from bitSegment4 + resultArray[2][0] >> 32, // overflow from bitSegment4 + bitSegment4.overflowCount) + let bitSegment1 = UInt128._variadicAdditionWithOverflowCount( + resultArray[0][0], + resultArray[0][1] >> 32, // overflow from bitSegment3 + resultArray[1][0] >> 32, // overflow from bitSegment3 + bitSegment3.overflowCount) + + // Shift and merge the results into 64 bit groups, adding in overflows as we go. + let lowerLowerBits = UInt128._variadicAdditionWithOverflowCount( + bitSegment8, + bitSegment7.truncatedValue << 32) + let upperLowerBits = UInt128._variadicAdditionWithOverflowCount( + bitSegment7.truncatedValue >> 32, + bitSegment6.truncatedValue, + bitSegment5.truncatedValue << 32, + lowerLowerBits.overflowCount) + let lowerUpperBits = UInt128._variadicAdditionWithOverflowCount( + bitSegment5.truncatedValue >> 32, + bitSegment4.truncatedValue, + bitSegment3.truncatedValue << 32, + upperLowerBits.overflowCount) + let upperUpperBits = UInt128._variadicAdditionWithOverflowCount( + bitSegment3.truncatedValue >> 32, + bitSegment1.truncatedValue, + lowerUpperBits.overflowCount) + + // Bring the 64bit unsigned integer results together into a high and low 128bit unsigned integer result. + return (high: UInt128(upperBits: upperUpperBits.truncatedValue, lowerBits: lowerUpperBits.truncatedValue), + low: UInt128(upperBits: upperLowerBits.truncatedValue, lowerBits: lowerLowerBits.truncatedValue)) + } + + /// Takes a variable amount of 64bit Unsigned Integers and adds them together, + /// tracking the total amount of overflows that occurred during addition. + /// + /// - Parameter addends: + /// Variably sized list of UInt64 values. + /// - Returns: + /// A tuple containing the truncated result and a count of the total + /// amount of overflows that occurred during addition. + private static func _variadicAdditionWithOverflowCount(_ addends: UInt64...) -> (truncatedValue: UInt64, overflowCount: UInt64) { + var sum: UInt64 = 0 + var overflowCount: UInt64 = 0 + + addends.forEach { addend in + let interimSum = sum.addingReportingOverflow(addend) + if interimSum.overflow { + overflowCount += 1 + } + sum = interimSum.partialValue + } + + return (truncatedValue: sum, overflowCount: overflowCount) + } + + public func dividedReportingOverflow(by rhs: UInt128) -> (partialValue: UInt128, overflow: Bool) { + guard rhs != 0 else { + return (self, true) + } + + let quotient = self.quotientAndRemainder(dividingBy: rhs).quotient + 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: Bool) { + guard rhs != 0 else { + return (self, true) + } + + let remainder = self.quotientAndRemainder(dividingBy: rhs).remainder + return (remainder, false) + } + + public func quotientAndRemainder(dividingBy rhs: UInt128) -> (quotient: UInt128, remainder: UInt128) { + return rhs._quotientAndRemainderFullWidth(dividingBy: (high: 0, low: self)) + } + + /// Provides the quotient and remainder when dividing the provided value by self. + internal func _quotientAndRemainderFullWidth(dividingBy dividend: (high: UInt128, low: UInt128)) -> (quotient: UInt128, remainder: UInt128) { + let divisor = self + let numeratorBitsToWalk: UInt128 + + if dividend.high > 0 { + numeratorBitsToWalk = dividend.high.significantBits + 128 - 1 + } else if dividend.low == 0 { + return (0, 0) + } else { + numeratorBitsToWalk = dividend.low.significantBits - 1 + } + + // The below algorithm was adapted from: + // https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_.28unsigned.29_with_remainder + + precondition(self != 0, "Division by 0") + + var quotient = UInt128.min + var remainder = UInt128.min + + for numeratorShiftWidth in (0...numeratorBitsToWalk).reversed() { + remainder <<= 1 + remainder |= UInt128._bitFromDoubleWidth(at: numeratorShiftWidth, for: dividend) + + if remainder >= divisor { + remainder -= divisor + quotient |= 1 << numeratorShiftWidth + } + } + + return (quotient, remainder) + } + + /// Returns the bit stored at the given position for the provided double width UInt128 input. + /// + /// - parameter at: position to grab bit value from. + /// - parameter for: the double width UInt128 data value to grab the + /// bit from. + /// - returns: single bit stored in a UInt128 value. + internal static func _bitFromDoubleWidth(at bitPosition: UInt128, for input: (high: UInt128, low: UInt128)) -> UInt128 { + switch bitPosition { + case 0: + return input.low & 1 + case 1...127: + return input.low >> bitPosition & 1 + case 128: + return input.high & 1 + default: + return input.high >> (bitPosition - 128) & 1 + } } } -public func +(lhs: UInt128, rhs: UInt128) -> UInt128 { - precondition(~lhs >= rhs, "Addition overflow!") - let (result, _) = UInt128.addWithOverflow(lhs, rhs) - return result -} - -public func +=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs + rhs -} - -prefix public func ++(lhs: inout UInt128) -> UInt128 { - lhs = lhs + 1 - return lhs -} - -postfix public func ++(lhs: inout UInt128) -> UInt128 { - let result = lhs - lhs = lhs + 1 - return result -} +// MARK: - BinaryInteger Conformance -public func -(lhs: UInt128, rhs: UInt128) -> UInt128 { - precondition(lhs >= rhs, "Integer underflow") - let (result, _) = UInt128.subtractWithOverflow(lhs, rhs) - return result -} +extension UInt128 : BinaryInteger { + // MARK: Instance Properties + + public static var bitWidth : Int { return 128 } -public func -=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs - rhs -} -prefix public func --(lhs: inout UInt128) -> UInt128 { - lhs = lhs - 1 - return lhs -} + // MARK: Instance Methods -postfix public func --(lhs: inout UInt128) -> UInt128 { - let result = lhs - lhs = lhs - 1 - return result -} + public var words: [UInt] { + guard self != UInt128.min else { + return [] + } -public func /(lhs: UInt128, rhs: UInt128) -> UInt128 { - let (result, _) = UInt128.divideWithOverflow(lhs, rhs) - return result -} + var words: [UInt] = [] -public func /=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs / rhs -} + for currentWord in 0 ... self.bitWidth / UInt.bitWidth { + let shiftAmount: UInt64 = UInt64(UInt.bitWidth) * UInt64(currentWord) + let mask = UInt64(UInt.max) + var shifted = self -public func %(lhs: UInt128, rhs: UInt128) -> UInt128 { - let (result, _) = UInt128.remainderWithOverflow(lhs, rhs) - return result -} + if shiftAmount > 0 { + shifted &>>= UInt128(upperBits: 0, lowerBits: shiftAmount) + } -public func %=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs % rhs -} + let masked: UInt128 = shifted & UInt128(upperBits: 0, lowerBits: mask) -public func *(lhs: UInt128, rhs: UInt128) -> UInt128 { - let result = UInt128.multiplyWithOverflow(lhs, rhs) - precondition(result.overflow == false, "Multiplication overflow!") - return result.0 -} + words.append(UInt(masked.value.lowerBits)) + } + return words + } -public func *=(lhs: inout UInt128, rhs: UInt128) { - lhs = lhs * rhs -} + public var trailingZeroBitCount: Int { + let mask: UInt128 = 1 + var bitsToWalk = self + + for currentPosition in 0...128 { + if bitsToWalk & mask == 1 { + return currentPosition + } + bitsToWalk >>= 1 + } + + return 128 + } + + // MARK: Initializers + + public init?(exactly source: T) { + if source.isZero { + self = UInt128() + } + else if source.exponent < 0 || source.rounded() != source { + return nil + } + else { + self = UInt128(UInt64(source)) + } + } + + public init(_ source: T) { + self.init(UInt64(source)) + } -// MARK: - Division and Modulus Combined Operator - -infix operator /% : AssignmentPrecedence - -/// Division and Modulus combined. Someone [else's] smart take on the -/// [integer division with remainder] algorithm. -/// -/// [else's]: -/// https://github.com/calccrypto/uint128_t -/// [integer division with remainder]: -/// https://en.wikipedia.org/wiki/Division_algorithm#Integer_division_.28unsigned.29_with_remainder -public func /%(dividend: UInt128, divisor: UInt128) -> (quotient: UInt128, remainder: UInt128) { - // Naughty boy, trying to divide by 0. - precondition(divisor != 0, "Division by 0") - // x/1 = x - if divisor == 1 { - return (dividend, 0) - } - // x/x = 1 - if dividend == divisor { - return (1, 0) - } - // 0/x = 0 - if dividend == 0 { - return (0, 0) - } - // x = y/z, when y < z, x = 0, r: y - // This would happen with below logic, but doing it now saves a few cycles. - if dividend < divisor { - return (0, dividend) - } - // Prime the result making the remainder equal the dividend. This will get - // decremented until no further even divisions can be made. - var result: (quotient: UInt128, remainder: UInt128) = (0, dividend) - // Initially shift the divisor left by significant bit difference so that quicker - // division can take place. IE: Discover GCD (Greatest Common Divisor). - // This value will get shifted right as the algorithm gets closer to the final solution. - var shiftedDivisor = divisor << (dividend.significantBits - divisor.significantBits) - // Initially shift 1 by the same amount as shiftedDivisor. Subtracting shiftedDivisor - // from dividend will be equal to that many subtractions of divisor from dividend. - var adder: UInt128 = 1 << (dividend.significantBits - divisor.significantBits) - // Remainder cannot be allowed to get below the divisor. - while result.remainder >= divisor { - // If remainder is great than shiftedDivisor we need to loop again as our - // bit shift is to high for even division. - if result.remainder >= shiftedDivisor { - result.remainder -= shiftedDivisor - result.quotient += adder + // MARK: Type Methods + + public static func /(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 { + let result = lhs.dividedReportingOverflow(by: rhs) + + return result.partialValue + } + + public static func /=(_ lhs: inout UInt128, _ rhs: UInt128) { + lhs = lhs / rhs + } + + public static func %(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 { + let result = lhs.remainderReportingOverflow(dividingBy: rhs) + + return result.partialValue + } + + public static func %=(_ lhs: inout UInt128, _ rhs: UInt128) { + lhs = lhs % rhs + } + + /// Performs a bitwise AND operation on 2 UInt128 data types. + public static func &=(_ lhs: inout UInt128, _ rhs: UInt128) { + let upperBits = lhs.value.upperBits & rhs.value.upperBits + let lowerBits = lhs.value.lowerBits & rhs.value.lowerBits + + lhs = UInt128(upperBits: upperBits, lowerBits: lowerBits) + } + + /// Performs a bitwise OR operation on 2 UInt128 data types. + public static func |=(_ lhs: inout UInt128, _ rhs: UInt128) { + let upperBits = lhs.value.upperBits | rhs.value.upperBits + let lowerBits = lhs.value.lowerBits | rhs.value.lowerBits + + lhs = UInt128(upperBits: upperBits, lowerBits: lowerBits) + } + + /// Performs a bitwise XOR operation on 2 UInt128 data types. + public static func ^=(_ lhs: inout UInt128, _ rhs: UInt128) { + let upperBits = lhs.value.upperBits ^ rhs.value.upperBits + let lowerBits = lhs.value.lowerBits ^ rhs.value.lowerBits + + lhs = UInt128(upperBits: upperBits, lowerBits: lowerBits) + } + + /// Perform a masked right SHIFT operation self. + /// + /// The masking operation will mask `rhs` against the highest + /// shift value that will not cause an overflowing shift before + /// performing the shift. IE: `rhs = 128` will become `rhs = 0` + /// and `rhs = 129` will become `rhs = 1`. + public static func &>>=(_ lhs: inout UInt128, _ rhs: UInt128) { + let shiftWidth = rhs.value.lowerBits & 127 + + switch shiftWidth { + case 0: return // Do nothing shift. + case 1...63: + let upperBits = lhs.value.upperBits >> shiftWidth + let lowerBits = (lhs.value.lowerBits >> shiftWidth) + (lhs.value.upperBits << (64 - shiftWidth)) + lhs = UInt128(upperBits: upperBits, lowerBits: lowerBits) + case 64: + // Shift 64 means move upper bits to lower bits. + lhs = UInt128(upperBits: 0, lowerBits: lhs.value.upperBits) + default: + let lowerBits = lhs.value.upperBits >> (shiftWidth - 64) + lhs = UInt128(upperBits: 0, lowerBits: lowerBits) } - // Protect ourselves from shifting too far too fast. - if result.remainder.significantBits <= shiftedDivisor.significantBits { - // Continue to shift down until we've reached our final even division. - shiftedDivisor >>= 1 - adder >>= 1 + } + + /// Perform a masked left SHIFT operation on self. + /// + /// The masking operation will mask `rhs` against the highest + /// shift value that will not cause an overflowing shift before + /// performing the shift. IE: `rhs = 128` will become `rhs = 0` + /// and `rhs = 129` will become `rhs = 1`. + public static func &<<=(_ lhs: inout UInt128, _ rhs: UInt128) { + let shiftWidth = rhs.value.lowerBits & 127 + + switch shiftWidth { + case 0: return // Do nothing shift. + case 1...63: + let upperBits = (lhs.value.upperBits << shiftWidth) + (lhs.value.lowerBits >> (64 - shiftWidth)) + let lowerBits = lhs.value.lowerBits << shiftWidth + lhs = UInt128(upperBits: upperBits, lowerBits: lowerBits) + case 64: + // Shift 64 means move lower bits to upper bits. + lhs = UInt128(upperBits: lhs.value.lowerBits, lowerBits: 0) + default: + let upperBits = lhs.value.lowerBits << (shiftWidth - 64) + lhs = UInt128(upperBits: upperBits, lowerBits: 0) } } - return result } -// MARK: - Comparable +// MARK: - UnsignedInteger Conformance + +extension UInt128 : UnsignedInteger {} -extension UInt128 : Comparable {} +// MARK: - Hashable Conformance -/// Comparable conforming operator that checks if the `lhs` UInt128 is -/// less than the `rhs` UInt128. -public func <(lhs: UInt128, rhs: UInt128) -> Bool { - if lhs.value.upperBits < rhs.value.upperBits { - return true - } else if lhs.value.upperBits == rhs.value.upperBits && lhs.value.lowerBits < rhs.value.lowerBits { - return true +extension UInt128 : Hashable { + public var hashValue: Int { + return self.value.lowerBits.hashValue ^ self.value.upperBits.hashValue } - return false } -public func <=(lhs: UInt128, rhs: UInt128) -> Bool { - if lhs < rhs || lhs == rhs { - return true +// MARK: - Numeric Conformance + +extension UInt128 : Numeric { + public static func +(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 { + precondition(~lhs >= rhs, "Addition overflow!") + let result = lhs.addingReportingOverflow(rhs) + return result.partialValue + } + public static func +=(_ lhs: inout UInt128, _ rhs: UInt128) { + lhs = lhs + rhs + } + public static func -(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 { + precondition(lhs >= rhs, "Integer underflow") + let result = lhs.subtractingReportingOverflow(rhs) + return result.partialValue + } + public static func -=(_ lhs: inout UInt128, _ rhs: UInt128) { + lhs = lhs - rhs + } + public static func *(_ lhs: UInt128, _ rhs: UInt128) -> UInt128 { + let result = lhs.multipliedReportingOverflow(by: rhs) + precondition(!result.overflow, "Multiplication overflow!") + return result.partialValue + } + public static func *=(_ lhs: inout UInt128, _ rhs: UInt128) { + lhs = lhs * rhs } - return false } -public func >(lhs: UInt128, rhs: UInt128) -> Bool { - if lhs.value.upperBits > rhs.value.upperBits { - return true - } else if lhs.value.upperBits == rhs.value.upperBits && lhs.value.lowerBits > rhs.value.lowerBits { - return true +// MARK: - Equatable Conformance + +extension UInt128 : Equatable { + /// Checks if the `lhs` is equal to the `rhs`. + public static func ==(lhs: UInt128, rhs: UInt128) -> Bool { + if lhs.value.lowerBits == rhs.value.lowerBits && lhs.value.upperBits == rhs.value.upperBits { + return true + } + return false } - return false } -public func >=(lhs: UInt128, rhs: UInt128) -> Bool { - if lhs > rhs || lhs == rhs { - return true +// MARK: - ExpressibleByIntegerLiteral Conformance + +extension UInt128 : ExpressibleByIntegerLiteral { + public init(integerLiteral value: IntegerLiteralType) { + self.init(upperBits: 0, lowerBits: UInt64(value)) } - return false } -// MARK: - Equatable +// MARK: - CustomStringConvertible Conformance + +extension UInt128 : CustomStringConvertible { + // MARK: Instance Properties + + public var description: String { + return self._valueToString() + } + + // MARK: Instance Methods + + /// Converts the stored value into a string representation. + /// - parameter radix: + /// The radix for the base numbering system you wish to have + /// the type presented in. + /// - parameter uppercase: + /// Determines whether letter components of the outputted string will be in + /// uppercase format or not. + /// - returns: + /// String representation of the stored UInt128 value. + internal func _valueToString(radix: Int = 10, uppercase: Bool = true) -> String { + precondition(radix > 1 && radix < 37, "radix must be within the range of 2-36.") + // Will store the final string result. + var result = String() + // Simple case. + if self == 0 { + result.append("0") + return result + } + // Used as the check for indexing through UInt128 for string interpolation. + var divmodResult = (quotient: self, remainder: UInt128(0)) + // Will hold the pool of possible values. + let characterPool = (uppercase) ? "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" : "0123456789abcdefghijklmnopqrstuvwxyz" + // Go through internal value until every base position is string(ed). + repeat { + divmodResult = divmodResult.quotient.quotientAndRemainder(dividingBy: UInt128(radix)) + let index = characterPool.characters.index(characterPool.startIndex, offsetBy: Int(divmodResult.remainder)) + result.insert(characterPool[index], at: result.startIndex) + } while divmodResult.quotient > 0 + return result + } +} -extension UInt128 : Equatable {} +// MARK: - CustomDebugStringConvertible Conformance -/// Equatable conforming operator that checks if the lhs UInt128 is -/// equal to the rhs UInt128. -public func ==(lhs: UInt128, rhs: UInt128) -> Bool { - if lhs.value.lowerBits == rhs.value.lowerBits && lhs.value.upperBits == rhs.value.upperBits { - return true +extension UInt128 : CustomDebugStringConvertible { + public var debugDescription: String { + return self.description } - return false } -// MARK: - CustomStringConvertible +// MARK: - Comparable Conformance -extension UInt128 : CustomStringConvertible { - public var description: String { - return self.toString() +extension UInt128 : Comparable { + public static func <(lhs: UInt128, rhs: UInt128) -> Bool { + if lhs.value.upperBits < rhs.value.upperBits { + return true + } else if lhs.value.upperBits == rhs.value.upperBits && lhs.value.lowerBits < rhs.value.lowerBits { + return true + } + return false } } -// MARK: - Extend SignedInteger for UInt128 +// MARK: - ExpressibleByStringLiteral Conformance -extension SignedInteger { - public init(_ value: UInt128) { - self.init(value.toIntMax()) +extension UInt128 : ExpressibleByStringLiteral { + // MARK: Initializers + + public init(stringLiteral value: StringLiteralType) { + self.init() + + if let result = UInt128._valueFromString(value) { + self = result + } + } + + // MARK: Type Methods + + internal static func _valueFromString(_ value: String) -> UInt128? { + let radix = UInt128._determineRadixFromString(value) + let inputString = radix == 10 ? value : String(value.dropFirst(2)) + + return UInt128(inputString, radix: radix) + } + + internal static func _determineRadixFromString(_ string: String) -> Int { + let radix: Int + + if string.hasPrefix("0b") { radix = 2 } + else if string.hasPrefix("0o") { radix = 8 } + else if string.hasPrefix("0x") { radix = 16 } + else { radix = 10 } + + return radix } } -// MARK: - Extend UnsignedInteger for UInt128 +// MARK: - Deprecated API -extension UnsignedInteger { - public init (_ value: UInt128) { - self.init(value.toUIntMax()) +extension UInt128 { + /// Initialize a UInt128 value from a string. + /// + /// - parameter source: the string that will be converted into a + /// UInt128 value. Defaults to being analyzed as a base10 number, + /// but can be prefixed with `0b` for base2, `0o` for base8 + /// or `0x` for base16. + @available(swift, deprecated: 3.2, renamed: "init(_:)") + public static func fromUnparsedString(_ source: String) throws -> UInt128 { + return try UInt128.init(source) } } -// MARK: - Extend String for UInt128 +// MARK: - BinaryFloatingPoint Interworking -extension String { +extension BinaryFloatingPoint { public init(_ value: UInt128) { - self.init() - self.append(value.toString()) + 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) + } + + public init?(exactly value: UInt128) { + if value.value.upperBits > 0 { + return nil + } + self = Self(value.value.lowerBits) } +} - public init(_ value: UInt128, radix: Int, uppercase: Bool = true) { - self.init() - let string = value.toString(radix: radix, uppercase: uppercase) - self.append(string) +// MARK: - String Interworking + +extension String { + /// Creates a string representing the given value in base 10, or some other + /// specified base. + /// + /// - Parameters: + /// - value: The UInt128 value to convert to a string. + /// - radix: The base to use for the string representation. `radix` must be + /// at least 2 and at most 36. The default is 10. + /// - uppercase: Pass `true` to use uppercase letters to represent numerals + /// or `false` to use lowercase letters. The default is `false`. + public init(_ value: UInt128, radix: Int = 10, uppercase: Bool = false) { + self = value._valueToString(radix: radix, uppercase: uppercase) } } diff --git a/Tests/UInt128Tests/UInt128Tests.swift b/Tests/UInt128Tests/UInt128Tests.swift index 89e4b6c..d946b77 100644 --- a/Tests/UInt128Tests/UInt128Tests.swift +++ b/Tests/UInt128Tests/UInt128Tests.swift @@ -1,5 +1,5 @@ // -// UInt128Tests.swift +// UInt128UnitTests.swift // // UInt128 unit test cases. // @@ -17,924 +17,1037 @@ // See the License for the specific language governing permissions and // limitations under the License. // + import XCTest -// import UInt128 module and mark as testable so we can, y'know, test it. + +// Import UInt128 module and mark as testable so we can, y'know, test it. @testable import UInt128 + // A UInt128 with a decently complicated bit pattern let bizarreUInt128: UInt128 = "0xf1f3f5f7f9fbfdfffefcfaf0f8f6f4f2" -/// This class' purpose in life is to test UInt128 like there's no tomorrow. -class UInt128Tests: XCTestCase { - let sanityValue = UInt128(upperBits: 1878316677920070929, lowerBits: 2022432965322149909) - static var allTests = { - return [ - ("testMax", testMax), - ("testMin", testMin), - ("testSignificantBits", testSignificantBits), - ("testBigEndian", testBigEndian), - ("testLittleEndian", testLittleEndian), - ("testSize", testSize) - ] - } - func testMax() { - XCTAssertEqual( - UInt128.max, - UInt128(upperBits: UInt64.max, lowerBits: UInt64.max) - ) - } - func testMin() { - XCTAssertEqual( - UInt128.min, - UInt128(upperBits: UInt64.min, lowerBits: UInt64.min) - ) - } - func testSignificantBits() { - // Verify 0 = 0 bits long. - XCTAssertEqual(UInt128(0).significantBits, 0) - // Verify max = 128 bits long. - XCTAssertEqual(UInt128.max.significantBits, 128) - // Verify lower.max = 64 bits long. - XCTAssertEqual(UInt128(UInt64.max).significantBits, 64) - // Verify 1 = 1 bits long. - XCTAssertEqual(UInt128(1).significantBits, 1) - } - func testBigEndian() { - let testUInt128Native: UInt128 = bizarreUInt128 - // Test whether native value matches expected mutated value. - #if arch(i386) || arch (x86_64) || arch(arm) || arch(arm64) - XCTAssertFalse(testUInt128Native.bigEndian == testUInt128Native) - #else - XCTAssertTrue(testUInt128Native.bigEndian == testUInt128Native) - #endif - // Test instantiation with bigEndian value matches expected value. - let testUInt128BigEndian = UInt128(bigEndian: testUInt128Native.bigEndian) - #if arch(i386) || arch (x86_64) || arch(arm) || arch(arm64) - XCTAssertTrue(testUInt128Native == testUInt128BigEndian) - #else - XCTAssertTrue(testUInt128Native.bigEndian == testUInt128BigEndian) - #endif - } - func testLittleEndian() { - let testUInt128Native = bizarreUInt128 - #if arch(i386) || arch (x86_64) || arch(arm) || arch(arm64) - XCTAssertTrue(testUInt128Native.littleEndian == testUInt128Native) - #else - XCTAssertFalse(testUInt128Native.bigEndian == testUInt128Native) - #endif - let testUInt128LittleEndian = UInt128(littleEndian: testUInt128Native.littleEndian) - #if arch(i386) || arch (x86_64) || arch(arm) || arch(arm64) - XCTAssertTrue( - testUInt128Native.littleEndian == testUInt128LittleEndian, - "Result:\(testUInt128LittleEndian), Original: \(testUInt128Native)" - ) - #else - XCTAssertTrue(testUInt128Native.littleEndian == testUInt128LittleEndian) - #endif - } - func testSize() { - XCTAssertEqual( - UInt128._sizeInBits, 128, - "UInt128 Must be 128 Bits in Size" - ) - XCTAssertEqual( - UInt128._sizeInBytes, 16, - "UInt128 Must be 16 Bytes in Size" - ) + +/// User tests that act as a basic smoke test on library functionality. +class SystemTests : XCTestCase { + func testCanReceiveAnInt() { + let expectedResult = UInt128(upperBits: 0, lowerBits: 1) + let testResult = UInt128(Int(1)) + XCTAssertEqual(testResult, expectedResult) + } + + func testCanBeSentToAnInt() { + let expectedResult: Int = 1 + let testResult = Int(UInt128(upperBits: 0, lowerBits: 1)) + XCTAssertEqual(testResult, expectedResult) + } + + func testIntegerLiteralInput() { + let expectedResult = UInt128(upperBits: 0, lowerBits: 1) + let testResult: UInt128 = 1 + XCTAssertEqual(testResult, expectedResult) + } + + func testCanReceiveAString() { + let expectedResult = UInt128(upperBits: 0, lowerBits: 1) + let testResult = try! UInt128(String("1")) + XCTAssertEqual(testResult, expectedResult) + } + + func testStringLiteralInput() { + let expectedResult = UInt128(upperBits: 0, lowerBits: 1) + let testResult: UInt128 = "1" + XCTAssertEqual(testResult, expectedResult) + } + + func testCanBeSentToAFloat() { + let expectedResult: Float = 1 + let testResult = Float(UInt128(upperBits: 0, lowerBits: 1)) + XCTAssertEqual(testResult, expectedResult) + } +} + +/// Test properties and methods that are not tied to protocol conformance. +class BaseTypeTests : XCTestCase { + func testSignificantBitsReturnsProperBitCount() { + var tests = [(input: UInt128(), + expected: UInt128(upperBits: 0, lowerBits: 0))] + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + expected: UInt128(upperBits: 0, lowerBits: 1))) + tests.append((input: UInt128(upperBits: 0, lowerBits: UInt64.max), + expected: UInt128(upperBits: 0, lowerBits: 64))) + tests.append((input: UInt128.max, + expected: UInt128(upperBits: 0, lowerBits: 128))) + + tests.forEach { test in + XCTAssertEqual(test.input.significantBits, test.expected) + } + } + + func testDesignatedInitializerProperlySetsInternalValue() { + var tests = [(input: (upperBits: UInt64.min, lowerBits: UInt64.min), + output: (upperBits: UInt64.min, lowerBits: UInt64.min))] + tests.append((input: (upperBits: UInt64.max, lowerBits: UInt64.max), + output: (upperBits: UInt64.max, lowerBits: UInt64.max))) + + tests.forEach { test in + let result = UInt128(upperBits: test.input.upperBits, + lowerBits: test.input.lowerBits) + + XCTAssertEqual(result.value.upperBits, test.output.upperBits) + XCTAssertEqual(result.value.lowerBits, test.output.lowerBits) + } + } + + func testDefaultInitializerSetsUpperAndLowerBitsToZero() { + let result = UInt128() + + XCTAssertEqual(result.value.upperBits, 0) + XCTAssertEqual(result.value.lowerBits, 0) + } + + func testInitWithUInt128() { + var tests = [UInt128()] + tests.append(UInt128(upperBits: 0, lowerBits: 1)) + tests.append(UInt128(upperBits: 0, lowerBits: UInt64.max)) + tests.append(UInt128.max) + + tests.forEach { test in + XCTAssertEqual(UInt128(test), test) + } + } + + func testStringInitializerWithEmptyString() { + XCTAssertThrowsError(try UInt128("")) + } + + func testStringInitializerWithSupportedNumberFormats() { + var tests = ["0b2"] + tests.append("0o8") + tests.append("0xG") + + try! tests.forEach { test in + XCTAssertThrowsError(try UInt128(test)) + } } } -class UInt128StringTests: XCTestCase { - let bizarreUInt128: UInt128 = "0xf1f3f5f7f9fbfdfffefcfaf0f8f6f4f2" - let sanityValue = UInt128(upperBits: 1878316677920070929, lowerBits: 2022432965322149909) - static var allTests = { - return [ - ("testFringeStringConversions", testFringeStringConversions), - ("testBinaryStringConversion", testBinaryStringConversion), - ("testOctalStringConversion", testOctalStringConversion), - ("testDecimalStringConversion", testDecimalStringConversion), - ("testHexadecimalStringConversion", testHexadecimalStringConversion) - ] - } - func testFringeStringConversions() { - // Test Empty String Input. - do { - let _ = try UInt128("") - XCTFail("Empty String to UInt128 didn't throw") - } catch UInt128Errors.emptyString { - XCTAssert(true) - } catch { - XCTFail("Empty String to UInt128 didn't throw correctly") - } - // Test out of bounds radix conversion - do { - let _ = try UInt128.fromParsedString("01234".utf16, radix: 37) - XCTFail("Invalid Radix didn't throw") - } catch UInt128Errors.invalidRadix { - XCTAssert(true) - } catch { - XCTFail("Invalid Radix didn't throw correctly.") - } - // Test 0 output from 0 input. - let zero = UInt128(0) - XCTAssert(zero.description == "0") - // Test String Conversion from UInt128 Input. - XCTAssertTrue( - try! UInt128(String(bizarreUInt128)) == bizarreUInt128, - "UInt128 Input to String Gave Incorrect Result" - ) - // Test literalStringConversion Failure - var invalidStringLiteral: UInt128 = "0z1234" - XCTAssertEqual( - invalidStringLiteral, UInt128(0), - "Invalid StringLiteral Didn't Return 0" - ) - // Test Inconceivable Failure - do { - invalidStringLiteral = try UInt128.fromParsedString("!".utf16, radix: 16) - XCTFail("Inconceiveable character didn't throw") - } catch UInt128Errors.invalidStringCharacter { - XCTAssert(true) - } catch { - XCTFail("Inconceivable character didn't throw correctly") - } - - // - let unicodeScalarLiteral = UInt128(unicodeScalarLiteral: "\u{0032}") - XCTAssertEqual( - unicodeScalarLiteral, UInt128(2), - "UnicodeScalarLiteral Didn't Return 2" - ) - // - let extendedGraphemeCluster = UInt128(extendedGraphemeClusterLiteral: "\u{00032}\u{00032}") - XCTAssertEqual( - extendedGraphemeCluster, UInt128(22), - "ExtendedGraephmeCluster Didn't Return 22" - ) - } - func testBinaryStringConversion() { - // String conversion test. - let binaryString = String.init([ - "0b00110100001000100011111000100010001101100011", - "1100001110100010001000111000001000100100000000", - "1000100010000000100010001000000010101" - ].joined(separator: "") - ) - XCTAssertTrue( - try! UInt128(binaryString!) == sanityValue, - "Basic Binary String to UInt128 conversion failed" - ) - // Valid string output conversion test (lowercase) - XCTAssertTrue( - String(sanityValue, radix: 2, uppercase: false) == String.init([ - "110100001000100011111000100010001101100011", - "1100001110100010001000111000001000100100000000", - "1000100010000000100010001000000010101" - ].joined(separator: "")), - "Basic UInt128 to Binary Lowercase String Conversion Failed" - ) - // Valid string output conversion test (uppercase) - XCTAssertTrue( - String(sanityValue, radix: 2, uppercase: true) == String.init([ - "110100001000100011111000100010001101100011", - "1100001110100010001000111000001000100100000000", - "1000100010000000100010001000000010101" - ].joined(separator: "")), - "Basic UInt128 to Binary Uppercase String Conversion Failed" - ) - // Invalid characters. - do { - let _ = try UInt128("0b002") - XCTFail("Binary String with Invalid Character didn't throw.") - } catch UInt128Errors.invalidStringCharacter { - XCTAssert(true) - } catch { - XCTFail("Binary String with Invalid Character didn't throw correctly.") - } - // Overflow. - do { - let _ = try UInt128([ - "0b11110100001000100011111000100010001101100011", - "1100001110100010001000111000001000100100000000", - "1000100010000000100010001000000010101010101" - ].joined(separator: "") - ) - XCTFail("Binary String Overflow didn't throw.") - } catch UInt128Errors.stringInputOverflow { - XCTAssert(true) - } catch { - XCTFail("Binary String Overflow didn't throw correctly.") - } - } - func testOctalStringConversion() { - // String conversion test. - XCTAssertTrue( - try! UInt128("0o00320421742106617035042160211001042004210025") == sanityValue, - "Basic Octal String to UInt128 conversion failed" - ) - // Valid string output conversion test (lowercase) - XCTAssertTrue( - String(sanityValue, radix: 8, uppercase: false) == "320421742106617035042160211001042004210025", - "Basic UInt128 to Octal Lowercase String Conversion Failed" - ) - // Valid string output conversion test (uppercase) - XCTAssertTrue( - String(sanityValue, radix: 8, uppercase: true) == "320421742106617035042160211001042004210025", - "Basic UInt128 to Octal Uppercase String Conversion Failed" - ) - // Invalid characters. - do { - let _ = try UInt128("0o008") - XCTFail("Octal String with Invalid Character didn't throw.") - } catch UInt128Errors.invalidStringCharacter { - XCTAssert(true) - } catch { - XCTFail("Octal String with Invalid Character didn't throw correctly.") - } - // Overflow. - do { - let _ = try UInt128("0o7654321076543210765432107654321765432107654") - XCTFail("Octal String overflow didn't throw.") - } catch UInt128Errors.stringInputOverflow { - XCTAssert(true) - } catch { - XCTFail("Octal String overflow didn't throw correctly.") - } - } - func testDecimalStringConversion() { - // String input conversion test. - XCTAssertTrue( - try! UInt128("0034648827046971881013470724628828721173") == sanityValue, - "Basic Decimal String to UInt128 conversion failed" - ) - // Valid string output conversion test (lowercase) - XCTAssertTrue( - String(sanityValue, radix: 10, uppercase: false) == "34648827046971881013470724628828721173", - "Basic UInt128 to Decimal Lowercase String Conversion Failed" - ) - // Valid string output conversion test (uppercase) - XCTAssertTrue( - String(sanityValue, radix: 10, uppercase: true) == "34648827046971881013470724628828721173", - "Basic UInt128 to Decimal Uppercase String Conversion Failed" - ) - // Invalid character. - do { - let _ = try UInt128("00a") - XCTFail("Decimal String with Invalid Character didn't throw.") - } catch UInt128Errors.invalidStringCharacter { - XCTAssert(true) - } catch { - XCTFail("Decimal String with Invalid Character didn't throw correctly.") - } - // Overflow. - do { - let _ = try UInt128("987654321098765432109876543210987654320") - XCTFail("Decimal String overflow didn't throw.") - } catch UInt128Errors.stringInputOverflow { - XCTAssert(true) - } catch { - XCTFail("Decimal String overflow didn't throw correctly.") - } - } - func testHexadecimalStringConversion() { - // Valid string input conversion test. - XCTAssertTrue( - // StringLiteralConvertible - try! UInt128("0x001A111F111B1E1D111C11201110111015") == sanityValue, - "Basic Hexadecimal String to UInt128 Conversion Failed" - ) - // Valid string output conversion test (lowercase) - XCTAssertTrue( - String(sanityValue, radix: 16, uppercase: false) == "1a111f111b1e1d111c11201110111015", - "Basic UInt128 to Hexadecimal Lowercase String Conversion Failed" - ) - // Valid string output conversion test (uppercase) - XCTAssertTrue( - String(sanityValue, radix: 16, uppercase: true) == "1A111F111B1E1D111C11201110111015", - "Basic UInt128 to Hexadecimal Uppercase String Conversion Failed" - ) - // Invalid character. - do { - let _ = try UInt128("00g") - XCTFail("Hexadecimal String with Invalid Character Didn't Throw.") - } catch UInt128Errors.invalidStringCharacter { - XCTAssert(true) - } catch { - XCTFail("Hexadecimal String with Invalid Character Didn't Throw Correctly.") - } - // Overflow. - do { - let _ = try UInt128("0xfedcba9876543210fedcba9876543210f") - XCTFail("Hexadecimal string overflow didn't throw.") - } catch UInt128Errors.stringInputOverflow { - XCTAssert(true) - } catch { - XCTFail("Hexadecimal string overflow didn't throw correctly.") - } - } - /*func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock { - // Put the code you want to measure the time of here. - } - }*/ + +class FixedWidthIntegerTests : XCTestCase { + func testNonzeroBitCount() { + var tests = [(input: UInt128.min, result: 0)] + tests.append((input: UInt128(1), result: 1)) + tests.append((input: UInt128(3), result: 2)) + tests.append((input: UInt128(UInt64.max), result: 64)) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), result: 1)) + tests.append((input: UInt128(upperBits: 3, lowerBits: 0), result: 2)) + tests.append((input: UInt128.max, result: 128)) + + tests.forEach { test in + XCTAssertEqual(test.input.nonzeroBitCount, test.result) + } + } + + func testLeadingZeroBitCount() { + var tests = [(input: UInt128.min, result: 128)] + tests.append((input: UInt128(1), result: 127)) + tests.append((input: UInt128(UInt64.max), result: 64)) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), result: 63)) + tests.append((input: UInt128.max, result: 0)) + + tests.forEach { test in + XCTAssertEqual(test.input.leadingZeroBitCount, test.result) + } + } + + func endianTests() -> [(input: UInt128, byteSwapped: UInt128)] { + var tests = [(input: UInt128(), byteSwapped: UInt128())] + tests.append((input: UInt128(1), + byteSwapped: UInt128(upperBits: 72057594037927936, lowerBits: 0))) + tests.append((input: UInt128(upperBits: 17434549027881090559, lowerBits: 18373836492640810226), + byteSwapped: UInt128(upperBits: 17506889200551263486, lowerBits: 18446176699804939249))) + return tests + } + + func testBigEndianProperty() { + endianTests().forEach { test in + #if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) + let expectedResult = test.byteSwapped + #else + let expectedResult = test.input + #endif + + XCTAssertEqual(test.input.bigEndian, expectedResult) + } + } + + func testBigEndianInitializer() { + endianTests().forEach { test in + #if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) + let expectedResult = test.byteSwapped + #else + let expectedResult = test.input + #endif + + XCTAssertEqual(UInt128(bigEndian: test.input), expectedResult) + } + } + + func testLittleEndianProperty() { + endianTests().forEach { test in + #if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) + let expectedResult = test.input + #else + let expectedResult = test.byteSwapped + #endif + + XCTAssertEqual(test.input.littleEndian, expectedResult) + } + } + + func testLittleEndianInitializer() { + endianTests().forEach { test in + #if arch(i386) || arch(x86_64) || arch(arm) || arch(arm64) + let expectedResult = test.input + #else + let expectedResult = test.byteSwapped + #endif + + XCTAssertEqual(UInt128(littleEndian: test.input), expectedResult) + } + } + + func testByteSwappedProperty() { + endianTests().forEach { test in + XCTAssertEqual(test.input.byteSwapped, test.byteSwapped) + } + } + + func testInitWithTruncatingBits() { + let testResult = UInt128(_truncatingBits: UInt.max) + XCTAssertEqual(testResult, UInt128(upperBits: 0, lowerBits: UInt64(UInt.max))) + } + + func testAddingReportingOverflow() { + // 0 + 0 = 0 + var tests = [(augend: UInt128.min, addend: UInt128.min, + sum: (partialValue: UInt128.min, overflow: false))] + // UInt128.max + 0 = UInt128.max + tests.append((augend: UInt128.max, addend: UInt128.min, + 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: true))) + // UInt128.max + 2 = 1, with overflow + tests.append((augend: UInt128.max, addend: UInt128(2), + 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: false))) + + tests.forEach { test in + let sum = test.augend.addingReportingOverflow(test.addend) + XCTAssertEqual(sum.partialValue, test.sum.partialValue) + XCTAssertEqual(sum.overflow, test.sum.overflow) + } + } + + func testSubtractingReportingOverflow() { + // 0 - 0 = 0 + var tests = [(minuend: UInt128.min, subtrahend: UInt128.min, + difference: (partialValue: UInt128.min, overflow: false))] + // Uint128.max - 0 = UInt128.max + tests.append((minuend: UInt128.max, subtrahend: UInt128.min, + 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: false))) + // UInt64.max + 1 - 1 = UInt64.max + tests.append((minuend: UInt128(upperBits: 1, lowerBits: 0), subtrahend: UInt128(1), + 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: true))) + // 0 - 2 = UInt128.max - 1, with overflow + tests.append((minuend: UInt128.min, subtrahend: UInt128(2), + difference: (partialValue: (UInt128.max >> 1) << 1, overflow: true))) + + tests.forEach { test in + let difference = test.minuend.subtractingReportingOverflow(test.subtrahend) + XCTAssertEqual(difference.partialValue, test.difference.partialValue) + XCTAssertEqual(difference.overflow, test.difference.overflow) + } + } + + func testMultipliedReportingOverflow() { + // 0 * 0 = 0 + var tests = [(multiplier: UInt128.min, multiplicator: UInt128.min, + 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: false))) + // UInt128.max * 0 = 0 + tests.append((multiplier: UInt128.max, multiplicator: UInt128.min, + product: (partialValue: UInt128.min, overflow: false))) + // UInt128.max * 1 = UInt128.max + tests.append((multiplier: UInt128.max, multiplicator: UInt128(1), + 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: true))) + // UInt128.max * UInt128.max = 1, with overflow + tests.append((multiplier: UInt128.max, multiplicator: UInt128.max, + product: (partialValue: UInt128(1), overflow: true))) + + tests.forEach { test in + let product = test.multiplier.multipliedReportingOverflow(by: test.multiplicator) + XCTAssertEqual(product.partialValue, test.product.partialValue) + XCTAssertEqual(product.overflow, test.product.overflow) + } + } + + func testMultipliedFullWidth() { + var tests = [(multiplier: UInt128.min, multiplicator: UInt128.min, + product: (high: UInt128.min, low: UInt128.min))] + tests.append((multiplier: UInt128(1), multiplicator: UInt128(1), + product: (high: UInt128.min, low: UInt128(1)))) + tests.append((multiplier: UInt128(UInt64.max), multiplicator: UInt128(UInt64.max), + product: (high: UInt128.min, low: UInt128(upperBits: UInt64.max - 1, lowerBits: 1)))) + tests.append((multiplier: UInt128.max, multiplicator: UInt128.max, + product: (high: UInt128.max ^ 1, low: UInt128(1)))) + + tests.forEach { test in + let product = test.multiplier.multipliedFullWidth(by: test.multiplicator) + XCTAssertEqual( + product.high, test.product.high, + "\n\(test.multiplier) * \(test.multiplicator) == (high: \(test.product.high), low: \(test.product.low)) != (high: \(product.high), low: \(product.low))\n") + XCTAssertEqual( + product.low, test.product.low, + "\n\(test.multiplier) * \(test.multiplicator) == (high: \(test.product.high), low: \(test.product.low)) != (high: \(product.high), low: \(product.low))\n") + } + } + + 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: 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: 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: 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: 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: 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: 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: false), + remainder: (partialValue: UInt128(UInt64.max), overflow: false))) + return tests + } + + func testDividedReportingOverflow() { + divisionTests().forEach { test in + let quotient = test.dividend.dividedReportingOverflow(by: test.divisor) + XCTAssertEqual( + quotient.partialValue, test.quotient.partialValue, + "\(test.dividend) / \(test.divisor) == \(test.quotient.partialValue)") + XCTAssertEqual( + quotient.overflow, test.quotient.overflow, + "\(test.dividend) / \(test.divisor) has overflow? \(test.remainder.overflow)") + } + } + + func testBitFromDoubleWidth() { + var tests = [(input: (high: UInt128(1), low: UInt128.min), + position: UInt128.min, result: UInt128.min)] + tests.append((input: (high: UInt128(1), low: UInt128.min), + position: UInt128(128), result: UInt128(1))) + tests.append((input: (high: UInt128(2), low: UInt128.min), + position: UInt128(128), result: UInt128.min)) + tests.append((input: (high: UInt128(2), low: UInt128.min), + position: UInt128(129), result: UInt128(1))) + tests.append((input: (high: UInt128.min, low: UInt128(2)), + position: UInt128.min, result: UInt128.min)) + tests.append((input: (high: UInt128.min, low: UInt128(2)), + position: UInt128(1), result: UInt128(1))) + + tests.forEach { test in + let result = UInt128._bitFromDoubleWidth(at: test.position, for: test.input) + XCTAssertEqual( + result, test.result, + "\n\(test.input), bit \(test.position) != \(test.result)") + } + } + + func testDividingFullWidth() { + // (0, 1) / 1 = 1r0 + var tests = [(dividend: (high: UInt128.min, low: UInt128(1)), + divisor: UInt128(1), + result: (quotient: UInt128(1), remainder: UInt128.min))] + // (1, 0) / 1 = 0r0 + tests.append((dividend: (high: UInt128(1), low: UInt128.min), + divisor: UInt128(1), + result: (quotient: UInt128.min, remainder: UInt128.min))) + // (1, 0) / 2 = 170141183460469231731687303715884105728r0 + tests.append((dividend: (high: UInt128(1), low: UInt128.min), + divisor: UInt128(2), + result: (quotient: UInt128(stringLiteral: "170141183460469231731687303715884105728"), + remainder: UInt128.min))) + + tests.forEach { test in + let result = test.divisor.dividingFullWidth(test.dividend) + XCTAssertEqual( + result.quotient, test.result.quotient, + "\n\(test.dividend) / \(test.divisor) == \(test.result)") + XCTAssertEqual( + result.remainder, test.result.remainder, + "\n\(test.dividend) / \(test.divisor) == \(test.result)") + } + } + + func testRemainderReportingOverflow() { + divisionTests().forEach { test in + let remainder = test.dividend.remainderReportingOverflow(dividingBy: test.divisor) + XCTAssertEqual( + remainder.partialValue, test.remainder.partialValue, + "\(test.dividend) / \(test.divisor) has a remainder of \(test.remainder.partialValue)") + XCTAssertEqual( + remainder.overflow, test.remainder.overflow, + "\(test.dividend) / \(test.divisor) has overflow? \(test.remainder.overflow)") + } + } + + func testQuotientAndRemainder() { + divisionTests().forEach { test in + guard test.divisor != 0 else { return } + + let result = test.dividend.quotientAndRemainder(dividingBy: test.divisor) + XCTAssertEqual( + result.quotient, test.quotient.partialValue, + "\(test.dividend) / \(test.divisor) == \(test.quotient.partialValue)") + XCTAssertEqual( + result.remainder, test.remainder.partialValue, + "\(test.dividend) / \(test.divisor) has a remainder of \(test.remainder.partialValue)") + } + } } -class UInt128UnsignedIntegerTests: XCTestCase { - static var allTests = { - return [ - ("testUIntInputs", testUIntInputs), - ("testToUIntMax", testToUIntMax), - ("testHashValues", testHashValues), - ("testIndexTypes", testIndexTypes) - ] - } - func testUIntInputs() { - // Test UInt8 Input - XCTAssertEqual( - UInt128(UInt8.max).toUIntMax(), UInt8.max.toUIntMax(), - "UInt8.max Fed Into UInt128 Doesn't Equal UInt8.max" - ) - // Test UInt16 Input - XCTAssertEqual( - UInt128(UInt16.max).toUIntMax(), UInt16.max.toUIntMax(), - "UInt16.max Fed Into UInt128 Doesn't Equal UInt16.max" - ) - // Test UInt32 Input - XCTAssertEqual( - UInt128(UInt32.max).toUIntMax(), UInt32.max.toUIntMax(), - "UInt32.max Fed Into UInt128 Doesn't Equal UInt32.max" - ) - // Test UInt64 Input - XCTAssertEqual( - UInt128(UInt64.max).toUIntMax(), UInt64.max.toUIntMax(), - "UInt64.max Fed Into UInt64 Doesn't Equal UInt64.max" - ) - // Test UInt Input - XCTAssertEqual( - UInt128(UInt.max).toUIntMax(), UInt.max.toUIntMax(), - "UInt.max Fed Into UInt128 Doesn't Equal UInt.max" - ) - } - func testToUIntMax() { - XCTAssertEqual( - UInt128.max.toUIntMax(), UIntMax.max, - "UInt128.max Converted to UIntMax.max Doesn't Equal UIntMax.max" - ) - } - /// An imperfect test of hash values. This method will walk through - /// most of the possible values within a UInt128 type and make sure - /// that 2 consecutive hash values are not the same. - func testHashValues() { - var previousValue = UInt128.min - var currentValue = UInt128.min + 1 - while currentValue <= UInt128.max >> 1 { - currentValue = (currentValue << 1) + 1 - if currentValue.hashValue == previousValue.hashValue { - XCTFail("Hash Value is Not Unique") + +class BinaryIntegerTests : XCTestCase { + func testBitWidthEquals128() { + XCTAssertEqual(UInt128.bitWidth, 128) + } + + func testTrailingZeroBitCount() { + var tests = [(input: UInt128.min, expected: 128)] + tests.append((input: UInt128(1), expected: 0)) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), expected: 64)) + tests.append((input: UInt128.max, expected: 0)) + + tests.forEach { test in + XCTAssertEqual(test.input.trailingZeroBitCount, test.expected)} + } + + func testInitFailableFloatingPointExactlyExpectedSuccesses() { + var tests = [(input: Float(), result: UInt128())] + tests.append((input: Float(1), result: UInt128(1))) + tests.append((input: Float(1.0), result: UInt128(1))) + + tests.forEach { test in + XCTAssertEqual(UInt128(exactly: test.input), test.result) + } + } + + func testInitFailableFloatingPointExactlyExpectedFailures() { + var tests = [Float(1.1)] + tests.append(Float(0.1)) + + tests.forEach { test in + XCTAssertEqual(UInt128(exactly: test), nil) + } + } + + func testInitFloatingPoint() { + var tests = [(input: Float80(), result: UInt128())] + tests.append((input: Float80(0.1), result: UInt128())) + tests.append((input: Float80(1.0), result: UInt128(1))) + tests.append((input: Float80(UInt64.max), result: UInt128(UInt64.max))) + + tests.forEach { test in + XCTAssertEqual(UInt128(test.input), test.result) + } + } + + func test_word() { + let lowerBits = UInt64("100000000000000000000000000000001", radix: 2)! + let upperBits = UInt64("100000000000000000000000000000001", radix: 2)! + let testResult = UInt128(upperBits: upperBits, lowerBits: lowerBits) + + testResult.words.forEach { (currentWord) in + if UInt.bitWidth == 64 { + XCTAssertEqual(currentWord, 4294967297) } - previousValue = currentValue - } - } - func testIndexTypes() { - // Test Successor - XCTAssertEqual( - UInt128(0).successor(), 1, - "0.successor() does not equal 1" - ) - XCTAssertEqual( - UInt128(UInt64.max).successor(), UInt128(1) << 64, - "(UInt64.max).successor() Did Not Cross the Bit Boundary Properly" - ) - XCTAssertEqual( - UInt128.max.successor(), 0, - "Wraparound From Maximum Value Does Not Equal 0" - ) - // Test Predecessor - XCTAssertEqual( - UInt128(0).predecessor(), UInt128.max, - "Wraparound From 0 Down By 1 Does Not Equal UInt128.max" - ) - XCTAssertEqual( - UInt128(UInt128(1) << 64).predecessor(), UInt128(UInt64.max), - "(1 << 64).predecessor() Did Not Cross the Bit Boundary Properly" - ) + } + } + + func divisionTests() -> [(dividend: UInt128, divisor: UInt128, quotient: UInt128, remainder: UInt128)] { + // 0 / 1 = 0, remainder 0 + var tests = [(dividend: UInt128.min, divisor: UInt128(1), + quotient: UInt128.min, remainder: UInt128.min)] + // 2 / 1 = 2, remainder 0 + tests.append((dividend: UInt128(2), divisor: UInt128(1), + quotient: UInt128(2), remainder: UInt128.min)) + // 1 / 2 = 0, remainder 1 + tests.append((dividend: UInt128(1), divisor: UInt128(2), + quotient: UInt128(0), remainder: UInt128(1))) + // UInt128.max / UInt64.max = UInt128(upperBits: 1, lowerBits: 1), remainder 0 + tests.append((dividend: UInt128.max, divisor: UInt128(UInt64.max), + quotient: UInt128(upperBits: 1, lowerBits: 1), remainder: UInt128.min)) + // UInt128.max / UInt128.max = 1, remainder 0 + tests.append((dividend: UInt128.max, divisor: UInt128.max, + quotient: UInt128(1), remainder: UInt128.min)) + // UInt64.max / UInt128.max = 0, remainder UInt64.max + tests.append((dividend: UInt128(UInt64.max), divisor: UInt128.max, + quotient: UInt128.min, remainder: UInt128(UInt64.max))) + return tests + } + + func testDivideOperator() { + divisionTests().forEach { test in + let quotient = test.dividend / test.divisor + XCTAssertEqual( + quotient, test.quotient, + "\(test.dividend) / \(test.divisor) == \(test.quotient)") + } + } + + func testDivideEqualOperator() { + divisionTests().forEach { test in + var quotient = test.dividend + quotient /= test.divisor + XCTAssertEqual( + quotient, test.quotient, + "\(test.dividend) /= \(test.divisor) == \(test.quotient)") + } + } + + func moduloTests() -> [(dividend: UInt128, divisor: UInt128, remainder: UInt128)] { + // 0 % 1 = 0 + var tests = [(dividend: UInt128.min, divisor: UInt128(1), + remainder: UInt128.min)] + // 1 % 2 = 1 + tests.append((dividend: UInt128(1), divisor: UInt128(2), + remainder: UInt128(1))) + // 0 % UInt128.max = 0 + tests.append((dividend: UInt128.min, divisor: UInt128.max, + remainder: UInt128.min)) + // UInt128.max % UInt64.max = 0 + tests.append((dividend: UInt128.max, divisor: UInt128(UInt64.max), + remainder: UInt128.min)) + // UInt128.max % UInt128.max = 0 + tests.append((dividend: UInt128.max, divisor: UInt128.max, + remainder: UInt128.min)) + // UInt64.max % UInt128.max = UInt64.max + tests.append((dividend: UInt128(UInt64.max), divisor: UInt128.max, + remainder: UInt128(UInt64.max))) + return tests + } + + func testModuloOperator() { + moduloTests().forEach { test in + let remainder = test.dividend % test.divisor + XCTAssertEqual( + remainder, test.remainder, + "\(test.dividend) % \(test.divisor) == \(test.remainder)") + } + } + + func testModuloEqualOperator() { + moduloTests().forEach { test in + var remainder = test.dividend + remainder %= test.divisor + XCTAssertEqual( + remainder, test.remainder, + "\(test.dividend) %= \(test.divisor) == \(test.remainder)") + } + } + + func testBooleanAndEqualOperator() { + var tests = [(lhs: UInt128.min, rhs: UInt128.min, result: UInt128.min)] + tests.append((lhs: UInt128(1), rhs: UInt128(1), result: UInt128(1))) + tests.append((lhs: UInt128.min, rhs: UInt128.max, result: UInt128.min)) + tests.append((lhs: UInt128(upperBits: UInt64.min, lowerBits: UInt64.max), + rhs: UInt128(upperBits: UInt64.max, lowerBits: UInt64.min), + result: UInt128.min)) + tests.append((lhs: UInt128(upperBits: 17434549027881090559, lowerBits: 18373836492640810226), + rhs: UInt128(upperBits: 17506889200551263486, lowerBits: 18446176699804939249), + result: UInt128(upperBits: 17361645879185571070, lowerBits: 18373836492506460400))) + tests.append((lhs: UInt128.max, rhs: UInt128.max, result: UInt128.max)) + + tests.forEach { test in + var result = test.lhs + result &= test.rhs + XCTAssertEqual(result, test.result) + } + } + + func testBooleanOrEqualOperator() { + var tests = [(lhs: UInt128.min, rhs: UInt128.min, result: UInt128.min)] + tests.append((lhs: UInt128(1), rhs: UInt128(1), result: UInt128(1))) + tests.append((lhs: UInt128.min, rhs: UInt128.max, result: UInt128.max)) + tests.append((lhs: UInt128(upperBits: UInt64.min, lowerBits: UInt64.max), + rhs: UInt128(upperBits: UInt64.max, lowerBits: UInt64.min), + result: UInt128.max)) + tests.append((lhs: UInt128(upperBits: 17434549027881090559, lowerBits: 18373836492640810226), + rhs: UInt128(upperBits: 17506889200551263486, lowerBits: 18446176699804939249), + result: UInt128(upperBits: 17579792349246782975, lowerBits: 18446176699939289075))) + tests.append((lhs: UInt128.max, rhs: UInt128.max, result: UInt128.max)) + + tests.forEach { test in + var result = test.lhs + result |= test.rhs + XCTAssertEqual(result, test.result) + } + } + + func testBooleanXorEqualOperator() { + var tests = [(lhs: UInt128.min, rhs: UInt128.min, result: UInt128.min)] + tests.append((lhs: UInt128(1), rhs: UInt128(1), result: UInt128.min)) + tests.append((lhs: UInt128.min, rhs: UInt128.max, result: UInt128.max)) + tests.append((lhs: UInt128(upperBits: UInt64.min, lowerBits: UInt64.max), + rhs: UInt128(upperBits: UInt64.max, lowerBits: UInt64.min), + result: UInt128.max)) + tests.append((lhs: UInt128(upperBits: 17434549027881090559, lowerBits: 18373836492640810226), + rhs: UInt128(upperBits: 17506889200551263486, lowerBits: 18446176699804939249), + result: UInt128(upperBits: 218146470061211905, lowerBits: 72340207432828675))) + tests.append((lhs: UInt128.max, rhs: UInt128.max, result: UInt128.min)) + + tests.forEach { test in + var result = test.lhs + result ^= test.rhs + XCTAssertEqual(result, test.result) + } + } + + func testMaskingRightShiftEqualOperatorStandardCases() { + var tests = [(input: UInt128(upperBits: UInt64.max, lowerBits: 0), + shiftWidth: UInt64(127), + expected: UInt128(upperBits: 0, lowerBits: 1))] + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), + shiftWidth: UInt64(64), + expected: UInt128(upperBits: 0, lowerBits: 1))) + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(1), + expected: UInt128())) + + tests.forEach { test in + var testValue = test.input + testValue &>>= UInt128(upperBits: 0, lowerBits: test.shiftWidth) + XCTAssertEqual(testValue, test.expected) + } + } + + func testMaskingRightShiftEqualOperatorEdgeCases() { + var tests = [(input: UInt128(upperBits: 0, lowerBits: 2), + shiftWidth: UInt64(129), + expected: UInt128(upperBits: 0, lowerBits: 1))] + tests.append((input: UInt128(upperBits: UInt64.max, lowerBits: 0), + shiftWidth: UInt64(128), + expected: UInt128(upperBits: UInt64.max, lowerBits: 0))) + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(0), + expected: UInt128(upperBits: 0, lowerBits: 1))) + + tests.forEach { test in + var testValue = test.input + testValue &>>= UInt128(upperBits: 0, lowerBits: test.shiftWidth) + XCTAssertEqual(testValue, test.expected) + } + } + + func testMaskingLeftShiftEqualOperatorStandardCases() { + let uint64_1_in_msb: UInt64 = 2 << 62 + var tests = [(input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(127), + expected: UInt128(upperBits: uint64_1_in_msb, lowerBits: 0))] + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(64), + expected: UInt128(upperBits: 1, lowerBits: 0))) + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(1), + expected: UInt128(upperBits: 0, lowerBits: 2))) + + tests.forEach { test in + var testValue = test.input + testValue &<<= UInt128(upperBits: 0, lowerBits: test.shiftWidth) + XCTAssertEqual(testValue, test.expected) + } + } + + func testMaskingLeftShiftEqualOperatorEdgeCases() { + var tests = [(input: UInt128(upperBits: 0, lowerBits: 2), + shiftWidth: UInt64(129), + expected: UInt128(upperBits: 0, lowerBits: 4))] + tests.append((input: UInt128(upperBits: 0, lowerBits: 2), + shiftWidth: UInt64(128), + expected: UInt128(upperBits: 0, lowerBits: 2))) + tests.append((input: UInt128(upperBits: 0, lowerBits: 1), + shiftWidth: UInt64(0), + expected: UInt128(upperBits: 0, lowerBits: 1))) + + tests.forEach { test in + var testValue = test.input + testValue &<<= UInt128(upperBits: 0, lowerBits: test.shiftWidth) + XCTAssertEqual(testValue, test.expected) + } } } -class UInt128StrideableTests: XCTestCase { - static var allTests = { - return [ - ("testAdvancedBy", testAdvancedBy), - ("testDistanceTo", testDistanceTo) - ] - } - func testAdvanced() { - XCTAssertEqual( - UInt128.min.advanced(by: 1), UInt128(integerLiteral: 1), - "0 Advanced by 1 Does Not Equal 1" - ) - XCTAssertEqual( - UInt128.min.advanced(by: -1), UInt128.max, - "0 Advanced by -1 Does Not Equal UInt128.max" - ) - XCTAssertEqual( - UInt128.max.advanced(by: 1), UInt128.min, - "UInt128.max Advanced by 1 Does not Equal UInt128.min" - ) - } - /// This is currently deprecated. - func testAdvancedBy() { - XCTAssertEqual( - UInt128.min.advancedBy(1), UInt128(integerLiteral: 1), - "0 Advanced by 1 Does Not Equal 1" - ) - XCTAssertEqual( - UInt128.min.advancedBy(-1), UInt128.max, - "0 Advanced by -1 Does Not Equal UInt128.max" - ) - XCTAssertEqual( - UInt128.max.advancedBy(1), UInt128.min, - "UInt128.max Advanced by 1 Does not Equal UInt128.min" - ) - } - func testDistance() { - XCTAssertEqual( - UInt128.min.distance(to: UInt128(Int.max)), Int.max, - "0 Advanced by Int.max Does Not Equal Int.max" - ) - XCTAssertEqual( - UInt128(Int.max).distance(to: 0), -Int.max, - "Distance to 0 from Int.max Doesn't Equal -Int.max" - ) - XCTAssertEqual( - UInt128(integerLiteral: 0).distance(to: UInt128(Int.max)), Int.max, - "Distance to Int.max from 0 Doesn't Equal Int.max" - ) - /* - These tests need to wait for such a time that preconditions can be properly checked - without requiring magical wizardry. - XCTAssertEqual( - UInt128(0).distanceTo(UInt128(Int.max) + 2), 0, - "Distance to Int.max + 1 from 0 Doesn't Equal 0" - ) - XCTAssertEqual( - UInt128.max.distanceTo(UInt128(1) << 70), 1, - "Things happened" - ) - */ - } - /// This is currently deprecated. - func testDistanceTo() { - XCTAssertEqual( - UInt128.min.distanceTo(UInt128(Int.max)), Int.max, - "0 Advanced by Int.max Does Not Equal Int.max" - ) - XCTAssertEqual( - UInt128(Int.max).distanceTo(0), -Int.max, - "Distance to 0 from Int.max Doesn't Equal -Int.max" - ) - XCTAssertEqual( - UInt128(integerLiteral: 0).distanceTo(UInt128(Int.max)), Int.max, - "Distance to Int.max from 0 Doesn't Equal Int.max" - ) - /* - These tests need to wait for such a time that preconditions can be properly checked - without requiring magical wizardry. - XCTAssertEqual( - UInt128(0).distanceTo(UInt128(Int.max) + 2), 0, - "Distance to Int.max + 1 from 0 Doesn't Equal 0" - ) - XCTAssertEqual( - UInt128.max.distanceTo(UInt128(1) << 70), 1, - "Things happened" - ) - */ + +class HashableTests : XCTestCase { + func hashableTests() -> [(input: UInt128, result: Int)] { + var tests = [(input: UInt128(), result: 0)] + tests.append((input: UInt128(1), result: 1)) + tests.append((input: UInt128(Int.max), result: Int.max)) + tests.append((input: try! UInt128("85070591730234615862769194512323794261"), + result: -1537228672809129302)) + return tests + } + + func testHashValueProperty() { + hashableTests().forEach { test in + XCTAssertEqual(test.input.hashValue, test.result) + } } } -class UInt128BitwiseOperationsTests: XCTestCase { - let allZeros = UInt128.allZeros - let allOnes = UInt128.max - static var allTests = { - return [ - ("testAllZeros", testAllZeros), - ("testAND", testAND), - ("testOR", testOR), - ("testXOR", testXOR), - ("testComplement", testComplement), - ("testShiftLeft", testShiftLeft), - ("testShiftRight", testShiftRight) - ] - } - func testAllZeros() { - XCTAssertEqual( - allZeros.value.upperBits, 0, - "Upper Bits of UInt128.allZeros Does Not Equal 0" - ) - XCTAssertEqual( - allZeros.value.lowerBits, 0, - "Lower Bits of UInt128.allZeros Does Not Equal 0" - ) - } - func testAND() { - XCTAssertEqual( - allZeros & allOnes, allZeros, - "All Bits Equal To 0 ANDed With All Bits Equal to 1 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - allZeros & allZeros, allZeros, - "All Bits Equal to 0 ANDed With All Bits Equal to 0 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - allOnes & allOnes, allOnes, - "All Bits Equal to 1 ANDed With All Bits Equal to 1 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - bizarreUInt128 & bizarreUInt128.bigEndian, try! UInt128("0xF0F0F4F0F0FAFCFEFEFCFAF0F0F4F0F0"), - "Complicated Bit Pattern ANDed With Its Big Endian Conversion Doesn't Equal Expected Value" - ) - var testValue = allZeros - testValue &= allOnes - XCTAssertEqual( - testValue, allZeros, - "All Bits Equal to 0 &= With All Bits Equal to 1 Does Not Return an All Zero Pattern" - ) - } - func testOR() { - XCTAssertEqual( - allZeros | allOnes, allOnes, - "All Bits Equal to 0 ORed With All Bits Equal to 1 Does Not Return an All One Pattern" - ) - XCTAssertEqual( - allZeros | allZeros, allZeros, - "All Bits Equal to 0 ORed With All Bits Equal to 0 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - allOnes | allOnes, allOnes, - "All Bits Equal to 1 ORed With All Bits Equal to 1 Does Not Retun an All One Pattern" - ) - XCTAssertEqual( - bizarreUInt128 | bizarreUInt128.bigEndian, try! UInt128("0xF3F7F7FFF9FBFDFFFFFDFBF9FFF7F7F3"), - "Complicated Bit Pattern ORed With Its Big Endian Conversion Doesn't Equal Expected Value" - ) - var testValue = allZeros - testValue += allOnes - XCTAssertEqual( - testValue, allOnes, - "All Bits Equal to 0 += With All Bits Equal to 1 Does Not Return an All One Pattern" - ) - } - func testXOR() { - XCTAssertEqual( - allZeros ^ allOnes, allOnes, - "All Bits Equal to 0 XORed With All Bits Equal to 1 Does Not Return an All One Pattern" - ) - XCTAssertEqual( - allZeros ^ allZeros, allZeros, - "All Bits Equal to 0 XORed With All Bits Equal to 0 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - allOnes ^ allOnes, allZeros, - "All Bits Equal to 1 XORed With All Bits Equal to 1 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - bizarreUInt128 ^ bizarreUInt128.bigEndian, try! UInt128("0x307030F09010101010101090F030703"), - "Complicated Bit Pattern XORed With Its Big Endian Conversion Doesn't Equal Expected Value" - ) - var testValue = bizarreUInt128 - testValue ^= bizarreUInt128.bigEndian - XCTAssertEqual( - testValue, try! UInt128("0x307030F09010101010101090F030703"), - "Complicated Bit Pattern ^= With All Its Big Endian Conversion Doesn't Equal Expected Value" - ) - } - func testComplement() { - XCTAssertEqual( - ~allZeros, allOnes, - "Complement of All Bits Equal to 0 Does Not Return an All One Pattern" - ) - XCTAssertEqual( - ~allOnes, allZeros, - "Complement of All Bits Equal to 1 Does Not Return an All Zero Pattern" - ) - XCTAssertEqual( - ~bizarreUInt128, try! UInt128("0xE0C0A08060402000103050F07090B0D"), - "Complement of Complicated Bit Pattern Doesn't Equal Expected Value" - ) - } - func testShiftLeft() { - XCTAssertEqual( - UInt128(1) << UInt128(upperBits: 1, lowerBits: 0), 0, - "1 Shifted by UIntMax.max + 1 Didn't Shift Out All Values" - ) - XCTAssertEqual( - UInt128(1) << 129, 0, - "1 Shifted by Bit Storage Area + 1 Didn't Shift Out All Values" - ) - XCTAssertEqual( - UInt128(1) << 128, 0, - "1 Shifted by Bit Storage Area Didn't Shift Out All Values" - ) - XCTAssertEqual( - bizarreUInt128 << 0, bizarreUInt128, - "Complicated Bit Pattern Shifted by 0 Bits Doesn't Equal Complicated Bit Pattern" - ) - XCTAssertEqual( - (bizarreUInt128 << 64).value.upperBits, bizarreUInt128.value.lowerBits, - "Complicated Bit Pattern Shifted by 64 Bits Doesn't Have upperBits Equal Original lowerBits" - ) - XCTAssertEqual( - (bizarreUInt128 << 64).value.lowerBits, 0, - "Complicated Bit Pattern Shifted by 64 Bits Has a Value in Lower 64 Bits" - ) - XCTAssertEqual( - try! UInt128("0b101") << 3, 40, - "5 Shifted 3 Bits Doesn't Equal 40" - ) - XCTAssertEqual( - try! UInt128("0b1101") << 67, try! UInt128("0x680000000000000000"), - "13 Shifted 67 Bits Doesn't Equal Expected Value" - ) - var testValue: UInt128 = 5 - testValue <<= 3 - XCTAssertEqual( - testValue, 40, - "5 <<= 3 Doesn't Equal 40" - ) - } - func testShiftRight() { - XCTAssertEqual( - bizarreUInt128 >> UInt128(upperBits: 1, lowerBits: 0), 0, - "Complicated Number Shifted by UIntMax.max + 1 Didn't Shift Out All Values" - ) - XCTAssertEqual( - bizarreUInt128 >> 129, 0, - "Complicated Number by Bit Storage Area + 1 Didn't Shift Out All Values" - ) - XCTAssertEqual( - bizarreUInt128 >> 128, 0, - "Complicated Number Shifted by Bit Storage Area Didn't Shift Out All Values" - ) - XCTAssertEqual( - bizarreUInt128 >> 0, bizarreUInt128, - "Complicated Bit Pattern Shifted by 0 Bits Doesn't Equal Complicated Bit Pattern" - ) - XCTAssertEqual( - (bizarreUInt128 >> 64).value.lowerBits, bizarreUInt128.value.upperBits, - "Complicated Bit Pattern Shifted by 64 Bits Doesn't Have Lower 64 Bits Equal Original Upper 64 Bits" - ) - XCTAssertEqual( - (bizarreUInt128 >> 64).value.upperBits, 0, - "Complicated Bit Pattern Shifted by 64 Bits Has a Value in Upper 64 Bits" - ) - XCTAssertEqual( - try! UInt128("0b101000") >> 3, 5, - "40 Shifted 3 Bits Doesn't Equal 5" - ) - XCTAssertEqual( - try! UInt128("0x680000000000000000") >> 67, try! UInt128("0b1101"), - "Large Number Shifted 67 Bits Doesn't Equal 15" - ) - var testValue: UInt128 = 40 - testValue >>= 3 - XCTAssertEqual( - testValue, 5, - "40 >>= 3 Doesn't Equal 5" - ) + +class NumericTests : XCTestCase { + func additionTests() -> [(augend: UInt128, addend: UInt128, sum: UInt128)] { + // 0 + 0 = 0 + var tests = [(augend: UInt128.min, addend: UInt128.min, sum: UInt128.min)] + // 1 + 1 = 2 + tests.append((augend: UInt128(1), addend: UInt128(1), sum: UInt128(2))) + // UInt128.max + 0 = UInt128.max + tests.append((augend: UInt128.max, addend: UInt128.min, sum: UInt128.max)) + // UInt64.max + 1 = UInt64.max + 1 + tests.append((augend: UInt128(UInt64.max), addend: UInt128(1), + sum: UInt128(upperBits: 1, lowerBits: 0))) + return tests + } + + func testAdditionOperator() { + additionTests().forEach { test in + let sum = test.augend + test.addend + XCTAssertEqual( + sum, test.sum, + "\(test.augend) + \(test.addend) == \(test.sum)") + } + } + + func testAdditionEqualOperator() { + additionTests().forEach { test in + var sum = test.augend + sum += test.addend + XCTAssertEqual( + sum, test.sum, + "\(test.augend) += \(test.addend) == \(test.sum)") + } + } + + func subtractionTests() -> [(minuend: UInt128, subtrahend: UInt128, difference: UInt128)] { + // 0 - 0 = 0 + var tests = [(minuend: UInt128.min, subtrahend: UInt128.min, + difference: UInt128.min)] + // Uint128.max - 0 = UInt128.max + tests.append((minuend: UInt128.max, subtrahend: UInt128.min, + difference: UInt128.max)) + // UInt128.max - 1 = UInt128.max - 1 + tests.append((minuend: UInt128.max, subtrahend: UInt128(1), + difference: UInt128(upperBits: UInt64.max, lowerBits: (UInt64.max >> 1) << 1))) + // UInt64.max + 1 - 1 = UInt64.max + tests.append((minuend: UInt128(upperBits: 1, lowerBits: 0), subtrahend: UInt128(1), + difference: UInt128(UInt64.max))) + return tests + } + + func testSubtractionOperator() { + subtractionTests().forEach { test in + let difference = test.minuend - test.subtrahend + XCTAssertEqual( + difference, test.difference, + "\(test.minuend) - \(test.subtrahend) == \(test.difference)") + } + } + + func testSubtractionEqualOperator() { + subtractionTests().forEach { test in + var difference = test.minuend + difference -= test.subtrahend + XCTAssertEqual( + difference, test.difference, + "\(test.minuend) -= \(test.subtrahend) == \(test.difference)") + } + } + + func multiplicationTests() -> [(multiplier: UInt128, multiplicator: UInt128, product: UInt128)] { + // 0 * 0 = 0 + var tests = [(multiplier: UInt128.min, multiplicator: UInt128.min, + product: UInt128.min)] + // UInt64.max * UInt64.max = UInt128.max - UInt64.max - 1 + tests.append((multiplier: UInt128(UInt64.max), multiplicator: UInt128(UInt64.max), + product: UInt128(upperBits: (UInt64.max >> 1) << 1, lowerBits: 1))) + // UInt128.max * 0 = 0 + tests.append((multiplier: UInt128.max, multiplicator: UInt128.min, + product: UInt128.min)) + // UInt128.max * 1 = UInt128.max + tests.append((multiplier: UInt128.max, multiplicator: UInt128(1), + product: UInt128.max)) + return tests + } + + func testMultiplicationOperator() { + multiplicationTests().forEach { test in + let product = test.multiplier * test.multiplicator + XCTAssertEqual( + product, test.product, + "\(test.multiplier) * \(test.multiplicator) == \(test.product)") + } + } + + func testMultiplicationEqualOperator() { + multiplicationTests().forEach { test in + var product = test.multiplier + product *= test.multiplicator + XCTAssertEqual( + product, test.product, + "\(test.multiplier) *= \(test.multiplicator) == \(test.product)") + } } } -class UInt128IntegerArithmeticTests: XCTestCase { - static var allTests = { - return [ - ("testAddition", testAddition), - ("testSubtraction", testSubtraction), - ("testDivisionAndModulus", testDivisionAndModulus), - ("testMultiplication", testMultiplication) - ] - } - func testAddition() { - var mathOperation = UInt128.addWithOverflow(UInt128(UInt64.max), 1) - XCTAssert( - mathOperation.overflow == false && mathOperation.0 == UInt128(upperBits: 1, lowerBits: 0), - "Crossing the 64 Bit Boundary by 1 Didn't Give the Expected Result" - ) - mathOperation = UInt128.addWithOverflow(UInt128.max, 1) - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == 0, - "128 Bit Overflow by 1 Didn't Give the Expected Result" - ) - mathOperation = UInt128.addWithOverflow(0, UInt128.max) - XCTAssert( - mathOperation.overflow == false && mathOperation.0 == UInt128.max, - "Adding UInt128.max to 0 Doesn't Equal UInt128.max" - ) - mathOperation = UInt128.addWithOverflow(2, UInt128.max) - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == 1, - "Adding UInt128.max to 2 Doesn't Equal 1" - ) - mathOperation = UInt128.addWithOverflow(bizarreUInt128, bizarreUInt128.bigEndian) - let expectedResult = try! UInt128("0xE4E8ECF0EAF6FAFEFEFAF6EAF0ECE8E3") - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == expectedResult, - "Complicated Bit Pattern Added to its Big Endian Representation Didn't Give Expected Result" - ) - var testInteger: UInt128 = 2 - testInteger += 5 - XCTAssertEqual( - testInteger, 7, - "2 += 5 Doesn't Equal Expected Result" - ) - XCTAssertEqual( - ++testInteger, 8, - "Prefix Increment Does Not Equal Expected Result" - ) - XCTAssert( - testInteger++ == 8 && testInteger == 9, - "Postfix Increment Does Not Equal Expected Result" - ) - } - func testSubtraction() { - var mathOperation = UInt128.subtractWithOverflow(UInt128(UInt64.max) + 1, 1) - XCTAssert( - mathOperation.overflow == false && mathOperation.0 == UInt128(UInt64.max), - "Crossing the 64 Bit Boundary by 1 Didn't Give the Expected Result" - ) - mathOperation = UInt128.subtractWithOverflow(UInt128.min, 1) - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == UInt128.max, - "128 Bit Underflow by 1 Didn't Give the Expected Result" - ) - mathOperation = UInt128.subtractWithOverflow(UInt128.max, UInt128.max) - XCTAssert( - mathOperation.overflow == false && mathOperation.0 == 0, - "Subtracting Across the Whole Value Range Didn't Equal 0" - ) - mathOperation = UInt128.subtractWithOverflow(UInt128(UInt64.max), UInt128.max) - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == UInt128(UInt64.max) + 1, - "Underflow Across 64 Bit Boundaries Didn't Give the Expected Result" - ) - mathOperation = UInt128.subtractWithOverflow(bizarreUInt128, bizarreUInt128.bigEndian) - let expectedResult = try! UInt128("0xFEFEFEFF09010100FEFEFEF701010101") - XCTAssert( - mathOperation.overflow == true && mathOperation.0 == expectedResult, - "Complicated Bit Pattern's Big Endian Representation Subtracted From Itself Didn't Give the Expected Result" - ) - var testInteger: UInt128 = 7 - testInteger -= 2 - XCTAssertEqual( - testInteger, 5, - "7 -= 2 Doesn't Equal Expected Result" - ) - XCTAssertEqual( - --testInteger, 4, - "Prefix Decrement Doesn't Equal Expected Result" - ) - XCTAssert( - testInteger-- == 4 && testInteger == 3, - "Postfix Decrement Doesn't Equal Expected Result" - ) - } - func testDivisionAndModulus() { - var mathOperation = bizarreUInt128 /% 1 - XCTAssert( - mathOperation.quotient == bizarreUInt128 && mathOperation.remainder == 0, - "Complicated Bit Pattern / 1 Doesn't Equal Complicated Bit Pattern" - ) - mathOperation = bizarreUInt128 /% bizarreUInt128 - XCTAssert( - mathOperation.quotient == 1 && mathOperation.remainder == 0, - "Complicated Bit Pattern / Itself Doesn't Equal 1" - ) - mathOperation = 0 /% bizarreUInt128 - XCTAssert( - mathOperation.quotient == 0 && mathOperation.remainder == 0, - "0 / Complicated Bit Pattern Doesn't Equal 0" - ) - mathOperation = bizarreUInt128 /% bizarreUInt128.bigEndian - XCTAssert( - mathOperation.quotient == 0 && mathOperation.remainder == bizarreUInt128, - "Complicated Bit Pattern Divided by a Smaller Complicated Bit Pattern Doesn't Equal the First Bit Pattern" - ) - mathOperation = UInt128.max /% (UInt128(UInt64.max) + 1) - XCTAssert( - mathOperation.quotient == UInt128(UInt64.max) && mathOperation.remainder == UInt128(UInt64.max), - "Maximum Value Divided by Half the Bit Count of Maximum Value + 1 (Division Across 64 Bit Boundary) Doesn't Equal Half the Bit Count of Maximum Value" - ) - var newMathOperation = UInt128.max - newMathOperation /= UInt128(UInt64.max) + 1 - XCTAssertEqual( - newMathOperation, UInt128(UInt64.max), - "/= Doesn't Give the Same Result as /%'s Quotient" - ) - newMathOperation = UInt128.max - newMathOperation %= UInt128(UInt64.max) + 1 - XCTAssertEqual( - newMathOperation, UInt128(UInt64.max), - "%= Doesn't Give the Same Result as /%'s Remainder" - ) - } - func testMultiplication() { - var mathOperation = UInt128.multiplyWithOverflow(1, 1) - XCTAssert( - mathOperation.0 == 1 && mathOperation.overflow == false, - "1 * 1 Doesn't Equal 1" - ) - mathOperation = UInt128.multiplyWithOverflow(UInt128(UInt64.max), 2) - var expectedResult = try! UInt128("0x1FFFFFFFFFFFFFFFE") - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == false, - "Crossing the 64 Bit Boundary by 1 Bit Didn't Give the Correct Result" - ) - mathOperation = UInt128.multiplyWithOverflow(UInt128.max, 1) - XCTAssert( - mathOperation.0 == UInt128.max && mathOperation.overflow == false, - "UInt128.max Times 1 Doesn't Equal Expected Result" - ) - mathOperation = UInt128.multiplyWithOverflow(1 << 97, 1 << 33) - XCTAssert( - mathOperation.0 == 0 && mathOperation.overflow == true, - "LHS, 32bit Position 0 * RHS, 32bit Position 0 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(1 << 97, UInt128(UInt32.max)) - expectedResult = try! UInt128("0xFFFFFFFE000000000000000000000000") - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == true, - "LHS, 32bit Position 1 * RHS, 32bit Position 4 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(1 << 65, 1 << 65) - XCTAssert( - mathOperation.0 == 0 && mathOperation.overflow == true, - "LHS, 32bit Position 2 * RHS, 32bit Position 2 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(1 << 65, UInt128(UInt32.max) << 32) - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == true, - "LHS, 32bit Position 2 * RHS, 32bit Position 3 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(1 << 32, 1 << 96) - XCTAssert( - mathOperation.0 == 0 && mathOperation.overflow == true, - "LHS, 32bit Position 3 * RHS, 32bit Position 1 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(UInt128(UInt32.max) << 32, 1 << 65) - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == true, - "LHS, 32bit Position 3 * RHS, 32bit Position 2 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(UInt128(UInt32.max), 1 << 97) - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == true, - "LHS, 32bit Position 4 * RHS, 32bit Position 1 Overflow Check Failed" - ) - mathOperation = UInt128.multiplyWithOverflow(bizarreUInt128, bizarreUInt128.bigEndian) - expectedResult = try! UInt128("0b11110110110100010000100101011011111001100001000011011101111010010100001010110111000010010011110010110100100110000100110111010010") - XCTAssert( - mathOperation.0 == expectedResult && mathOperation.overflow == true, - "Complicated Number Multiplied by Its Big Endian Version Didn't Give Expected Result" - ) - var newMathOperation = UInt128(UInt64.max) - newMathOperation *= 2 - expectedResult = try! UInt128("0x1FFFFFFFFFFFFFFFE") - XCTAssertEqual( - newMathOperation, expectedResult, - "*= Didn't Give the Same Result as multiplyWithOverflow" - ) + +class EquatableTests : XCTestCase { + func testBooleanEqualsOperator() { + var tests = [(lhs: UInt128.min, + rhs: UInt128.min, result: true)] + tests.append((lhs: UInt128.min, + rhs: UInt128(1), result: false)) + tests.append((lhs: UInt128.max, + rhs: UInt128.max, result: true)) + tests.append((lhs: UInt128(UInt64.max), + rhs: UInt128(upperBits: UInt64.max, lowerBits: UInt64.min), result: false)) + tests.append((lhs: UInt128(upperBits: 1, lowerBits: 0), + rhs: UInt128(upperBits: 1, lowerBits: 0), result: true)) + tests.append((lhs: UInt128(upperBits: 1, lowerBits: 0), + rhs: UInt128(), result: false)) + + tests.forEach { test in + XCTAssertEqual(test.lhs == test.rhs, test.result) + } } } -class UInt128ComparableTests: XCTestCase { - static var allTests = { - return [ - ("testComparable", testComparable), - ("testEquatable", testEquatable) - ] - } - func testComparable() { - XCTAssertGreaterThan( - UInt128(UInt64.max) << 64, UInt128(UInt64.max), - "RHS Upper 64 Bits Equal to LHS Lower 64 Bits Didn't Compare Correctly" - ) - XCTAssertGreaterThan( - UInt128(1), 0, - "1 Isn't Greater Than 0" - ) - XCTAssertLessThan( - UInt128(UInt64.max), UInt128(UInt64.max) << 64, - "LHS Upper 64 Bits Equal to LHS 64 Bits Didn't Compare Correctly" - ) - XCTAssertLessThan( - UInt128(0), 1, - "0 Isn't Less Than 1" - ) - } - func testEquatable() { - XCTAssertEqual( - UInt128.max, UInt128.max, - "Max Doesn't Equal Max" - ) - XCTAssertEqual( - UInt64(UInt128(0)), 0, - "0 Doesn't Equal 0" - ) - XCTAssertNotEqual( - bizarreUInt128, bizarreUInt128.bigEndian, - "Complicated Pattern Equals its Big Endian Counterpart" - ) + +class ExpressibleByIntegerLiteralTests : XCTestCase { + func testInitWithIntegerLiteral() { + var tests = [(input: 0, result: UInt128())] + tests.append((input: 1, result: UInt128(upperBits: 0, lowerBits: 1))) + tests.append((input: Int.max, result: UInt128(upperBits: 0, lowerBits: UInt64(Int.max)))) + + tests.forEach { test in + XCTAssertEqual(UInt128(integerLiteral: test.input), test.result) + } + } +} + +class CustomStringConvertibleTests : XCTestCase { + func stringTests() -> [(input: UInt128, result: [Int: String])] { + var tests = [(input: UInt128(), result:[ + 2: "0", 8: "0", 10: "0", 16: "0", 18: "0", 36: "0"])] + tests.append((input: UInt128(1), result: [ + 2: "1", 8: "1", 10: "1", 16: "1", 18: "1", 36: "1"])) + tests.append((input: UInt128(UInt64.max), result: [ + 2: "1111111111111111111111111111111111111111111111111111111111111111", + 8: "1777777777777777777777", + 10: "18446744073709551615", + 16: "ffffffffffffffff", + 18: "2d3fgb0b9cg4bd2f", + 36: "3w5e11264sgsf"])) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), result: [ + 2: "10000000000000000000000000000000000000000000000000000000000000000", + 8: "2000000000000000000000", + 10: "18446744073709551616", + 16: "10000000000000000", + 18: "2d3fgb0b9cg4bd2g", + 36: "3w5e11264sgsg"])) + tests.append((input: UInt128.max, result: [ + 2: "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + 8: "3777777777777777777777777777777777777777777", + 10: "340282366920938463463374607431768211455", + 16: "ffffffffffffffffffffffffffffffff", + 18: "78a399ccdeb5bd6ha3184c0fh64da63", + 36: "f5lxx1zz5pnorynqglhzmsp33"])) + return tests + } + + func testDescriptionProperty() { + stringTests().forEach { test in + XCTAssertEqual(test.input.description, test.result[10]) + } + } + + func testStringDescribingInitializer() { + stringTests().forEach { test in + XCTAssertEqual(String(describing: test.input), test.result[10]) + } + } + + func testStringUInt128InitializerLowercased() { + stringTests().forEach { test in + test.result.forEach { result in + let (radix, result) = result + let testOutput = String(test.input, radix: radix) + XCTAssertEqual(testOutput, result) + } + } + } + + func testStringUInt128InitializerUppercased() { + stringTests().forEach { test in + test.result.forEach { result in + let (radix, result) = result + let testOutput = String(test.input, radix: radix, uppercase: true) + XCTAssertEqual(testOutput, result.uppercased()) + } + } + } + +} + +class CustomDebugStringConvertible : XCTestCase { + func stringTests() -> [(input: UInt128, result: String)] { + var tests = [(input: UInt128(), + result:"0")] + tests.append((input: UInt128(1), + result: "1")) + tests.append((input: UInt128(UInt64.max), + result: "18446744073709551615")) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), + result: "18446744073709551616")) + tests.append((input: UInt128.max, + result: "340282366920938463463374607431768211455")) + return tests + } + + + func testDebugDescriptionProperty() { + stringTests().forEach { test in + XCTAssertEqual(test.input.debugDescription, test.result) + } + } + + func testStringReflectingInitializer() { + stringTests().forEach { test in + XCTAssertEqual(String(reflecting: test.input), test.result) + } + } +} + +class ComparableTests : XCTestCase { + func testLessThanOperator() { + var tests = [(lhs: UInt128.min, rhs: UInt128(1), result: true)] + tests.append((lhs: UInt128.min, rhs: UInt128(upperBits: 1, lowerBits: 0), result: true)) + tests.append((lhs: UInt128(1), rhs: UInt128(upperBits: 1, lowerBits: 0), result: true)) + tests.append((lhs: UInt128(UInt64.max), rhs: UInt128.max, result: true)) + tests.append((lhs: UInt128.min, rhs: UInt128.min, result: false)) + tests.append((lhs: UInt128.max, rhs: UInt128.max, result: false)) + tests.append((lhs: UInt128.max, rhs: UInt128(UInt64.max), result: false)) + + tests.forEach { test in + XCTAssertEqual(test.lhs < test.rhs, test.result) + } + } +} + +class ExpressibleByStringLiteralTests : XCTestCase { + func stringTests() -> [(input: String, result: UInt128)] { + var tests = [(input: "", result: UInt128())] + tests.append((input: "0", result: UInt128())) + tests.append((input: "1", result: UInt128(1))) + tests.append((input: "99", result: UInt128(99))) + tests.append((input: "0b0101", result: UInt128(5))) + tests.append((input: "0o11", result: UInt128(9))) + tests.append((input: "0xFF", result: UInt128(255))) + tests.append((input: "0z1234", result: UInt128())) + return tests + } + + func testInitWithStringLiteral() { + stringTests().forEach { test in + XCTAssertEqual(UInt128(stringLiteral: test.input), test.result) + } + } + + func testEvaluatedWithStringLiteral() { + let binaryTest: UInt128 = "0b11" + XCTAssertEqual(binaryTest, UInt128(3)) + + let octalTest: UInt128 = "0o11" + XCTAssertEqual(octalTest, UInt128(9)) + + let decimalTest: UInt128 = "11" + XCTAssertEqual(decimalTest, UInt128(11)) + + let hexTest: UInt128 = "0x11" + XCTAssertEqual(hexTest, UInt128(17)) + } +} + +@available(swift, deprecated: 3.2) +class DeprecatedAPITests : XCTestCase { + func testFromUnparsedString() { + XCTAssertThrowsError(try UInt128.fromUnparsedString("")) + XCTAssertEqual(try UInt128.fromUnparsedString("1"), UInt128(1)) + } +} + +class FloatingPointInterworkingTests : XCTestCase { + func testNonFailableInitializer() { + var tests = [(input: UInt128(), output: Float(0))] + tests.append((input: UInt128(upperBits: 0, lowerBits: UInt64.max), + output: Float(UInt64.max))) + + tests.forEach { test in + XCTAssertEqual(Float(test.input), test.output) + } + } + + func testFailableInitializer() { + var tests = [(input: UInt128(), + output: Float(0) as Float?)] + tests.append((input: UInt128(upperBits: 0, lowerBits: UInt64.max), + output: Float(UInt64.max) as Float?)) + tests.append((input: UInt128(upperBits: 1, lowerBits: 0), + output: nil)) + + tests.forEach { test in + XCTAssertEqual(Float(exactly: test.input), test.output) + } + } + + func testSignBitIndex() { + var tests = [(input: UInt128.min, output: Int(-1))] + tests.append((input: UInt128.max, output: Int(127))) + + tests.forEach { test in + XCTAssertEqual(test.input.signBitIndex, test.output) + } } } diff --git a/UInt128.xcodeproj/project.pbxproj b/UInt128.xcodeproj/project.pbxproj index 3a38a8d..5a7a5b4 100644 --- a/UInt128.xcodeproj/project.pbxproj +++ b/UInt128.xcodeproj/project.pbxproj @@ -47,7 +47,6 @@ 481A30AF1F02FB9F00C4438A /* UInt128.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UInt128.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 48389B601EDB9F78008C1177 /* Playground.playground */ = {isa = PBXFileReference; lastKnownFileType = file.playground; path = Playground.playground; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.swift; }; OBJ_11 /* UInt128Tests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UInt128Tests.swift; sourceTree = ""; }; - OBJ_12 /* bin */ = {isa = PBXFileReference; lastKnownFileType = folder; path = bin; sourceTree = SOURCE_ROOT; }; OBJ_14 /* UInt128.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = UInt128.framework; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_15 /* UInt128Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = UInt128Tests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; path = Package.swift; sourceTree = ""; }; @@ -122,7 +121,6 @@ children = ( 48389B601EDB9F78008C1177 /* Playground.playground */, OBJ_6 /* Package.swift */, - OBJ_12 /* bin */, OBJ_7 /* Sources */, OBJ_9 /* Tests */, OBJ_13 /* Products */, @@ -258,16 +256,26 @@ OBJ_1 /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 9999; + LastUpgradeCheck = 0900; TargetAttributes = { + 167CA9BB1EFCF3E50091689C = { + LastSwiftMigration = 0900; + }; 481A309F1F02F8A000C4438A = { CreatedOnToolsVersion = 8.3.3; ProvisioningStyle = Automatic; }; 481A30AE1F02FB9F00C4438A = { CreatedOnToolsVersion = 8.3.3; + LastSwiftMigration = 0900; ProvisioningStyle = Automatic; }; + OBJ_16 = { + LastSwiftMigration = 0900; + }; + OBJ_23 = { + LastSwiftMigration = 0900; + }; }; }; buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "UInt128" */; @@ -390,6 +398,8 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TARGET_NAME = UInt128; }; @@ -415,6 +425,8 @@ SDKROOT = iphoneos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "iphonesimulator iphoneos"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; TARGET_NAME = UInt128; }; @@ -592,7 +604,8 @@ SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TARGET_NAME = UInt128; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -648,7 +661,8 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = "appletvsimulator appletvos"; - SWIFT_VERSION = 3.0; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = 3; TARGET_NAME = UInt128; TVOS_DEPLOYMENT_TARGET = 9.0; @@ -677,6 +691,8 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = macosx; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGET_NAME = UInt128; }; name = Debug; @@ -700,6 +716,8 @@ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; SKIP_INSTALL = YES; SUPPORTED_PLATFORMS = macosx; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGET_NAME = UInt128; }; name = Release; @@ -708,7 +726,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PLATFORM_DIR)/Developer/Library/Frameworks", @@ -718,6 +735,8 @@ LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGET_NAME = UInt128Tests; }; name = Debug; @@ -726,7 +745,6 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; - EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", "$(PLATFORM_DIR)/Developer/Library/Frameworks", @@ -736,6 +754,8 @@ LD_RUNPATH_SEARCH_PATHS = "@loader_path/../Frameworks @loader_path/Frameworks"; OTHER_LDFLAGS = "$(inherited)"; OTHER_SWIFT_FLAGS = "$(inherited)"; + SWIFT_SWIFT3_OBJC_INFERENCE = Default; + SWIFT_VERSION = 4.0; TARGET_NAME = UInt128Tests; }; name = Release; @@ -744,12 +764,36 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; DEBUG_INFORMATION_FORMAT = dwarf; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_NS_ASSERTIONS = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; OTHER_SWIFT_FLAGS = "-DXcode"; @@ -767,11 +811,34 @@ isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = s; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; OTHER_SWIFT_FLAGS = "-DXcode"; PRODUCT_NAME = "$(TARGET_NAME)"; diff --git a/UInt128.xcodeproj/xcshareddata/xcschemes/UInt128-macOS.xcscheme b/UInt128.xcodeproj/xcshareddata/xcschemes/UInt128-macOS.xcscheme index cf03e87..1ab0976 100644 --- a/UInt128.xcodeproj/xcshareddata/xcschemes/UInt128-macOS.xcscheme +++ b/UInt128.xcodeproj/xcshareddata/xcschemes/UInt128-macOS.xcscheme @@ -1,6 +1,6 @@