diff --git a/Package.swift b/Package.swift index a7689df..5eb1547 100644 --- a/Package.swift +++ b/Package.swift @@ -17,20 +17,10 @@ let package = Package( targets: [ .target( name: "ScaleCodec", - dependencies: [ - .product(name: "Tuples", package: "Tuples.swift"), - "DoubleWidth" - ]), - .target( - name: "DoubleWidth", - dependencies: []), + dependencies: [ .product(name: "Tuples", package: "Tuples.swift") ]), .testTarget( name: "ScaleCodecTests", - dependencies: ["ScaleCodec"]), - .testTarget( - name: "DoubleWidthTests", - dependencies: ["ScaleCodec"] - ) + dependencies: ["ScaleCodec"]) ] ) diff --git a/Sources/DoubleWidth/DoubleWidth.swift b/Sources/DoubleWidth/DoubleWidth.swift deleted file mode 100644 index 0f9ad46..0000000 --- a/Sources/DoubleWidth/DoubleWidth.swift +++ /dev/null @@ -1,778 +0,0 @@ -/// A fixed-width integer that has twice the bit width of its base type. -/// -/// You can use the `DoubleWidth` type to continue calculations with the result -/// of a full width arithmetic operation. Normally, when you perform a full -/// width operation, the result is a tuple of the high and low parts of the -/// result. -/// -/// let a = 2241543570477705381 -/// let b = 186319822866995413 -/// let c = a.multipliedFullWidth(by: b) -/// // c == (high: 22640526660490081, low: 7959093232766896457) -/// -/// The tuple `c` can't be used in any further comparisons or calculations. To -/// use this value, create a `DoubleWidth` instance from the result. You can -/// use the `DoubleWidth` instance in the same way that you would use any other -/// integer type. -/// -/// let d = DoubleWidth(a.multipliedFullWidth(by: b)) -/// // d == 417644001000058515200174966092417353 -/// -/// // Check the calculation: -/// print(d / DoubleWidth(a) == b) -/// // Prints "true" -/// -/// if d > Int.max { -/// print("Too big to be an 'Int'!") -/// } else { -/// print("Small enough to fit in an 'Int'") -/// } -/// // Prints "Too big to be an 'Int'!" -/// -/// The `DoubleWidth` type is not intended as a replacement for a variable-width -/// integer type. Nesting `DoubleWidth` instances, in particular, may result in -/// undesirable performance. -public struct DoubleWidth { - public typealias High = Base - public typealias Low = Base.Magnitude - -#if _endian(big) - internal var _storage: (high: High, low: Low) -#else - internal var _storage: (low: Low, high: High) -#endif - - /// The high part of the value. - public var high: High { - return _storage.high - } - - /// The low part of the value. - public var low: Low { - return _storage.low - } - - /// Creates a new instance from the given tuple of high and low parts. - /// - /// - Parameter value: The tuple to use as the source of the new instance's - /// high and low parts. - public init(_ value: (high: High, low: Low)) { -#if _endian(big) - self._storage = (high: value.0, low: value.1) -#else - self._storage = (low: value.1, high: value.0) -#endif - } - - // We expect users to invoke the public initializer above as demonstrated in - // the documentation (that is, by passing in the result of a full width - // operation). - // - // Internally, we'll need to create new instances by supplying high and low - // parts directly; ((double parentheses)) greatly impair readability, - // especially when nested: - // - // DoubleWidth((DoubleWidth((0, 0)), DoubleWidth((0, 0)))) - // - // For that reason, we'll include an internal initializer that takes two - // separate arguments. - internal init(_ _high: High, _ low: Low) { - self.init((_high, low)) - } - - public init() { - self.init(0, 0) - } -} - -extension DoubleWidth : CustomStringConvertible { - public var description: String { - return String(self, radix: 10) - } -} - -extension DoubleWidth : CustomDebugStringConvertible { - public var debugDescription: String { - return "(\(_storage.high), \(_storage.low))" - } -} - -extension DoubleWidth : Equatable { - public static func ==(lhs: DoubleWidth, rhs: DoubleWidth) -> Bool { - return lhs._storage.low == rhs._storage.low - && lhs._storage.high == rhs._storage.high - } -} - -extension DoubleWidth : Comparable { - public static func <(lhs: DoubleWidth, rhs: DoubleWidth) -> Bool { - if lhs._storage.high < rhs._storage.high { return true } - else if lhs._storage.high > rhs._storage.high { return false } - else { return lhs._storage.low < rhs._storage.low } - } -} - -extension DoubleWidth : Hashable { - public var hashValue: Int { - return _hashValue(for: self) - } - - public func hash(into hasher: inout Hasher) { - hasher.combine(low) - hasher.combine(high) - } -} - -extension DoubleWidth : Numeric { - public typealias Magnitude = DoubleWidth - - public var magnitude: Magnitude { - let result = Magnitude(Low(truncatingIfNeeded: _storage.high), _storage.low) - if Base.isSigned && _storage.high < (0 as High) { - return ~result &+ 1 - } else { - return result - } - } - - internal init(_ _magnitude: Magnitude) { - self.init(High(_magnitude._storage.high), _magnitude._storage.low) - } - - public init(_ source: T) { - guard let result = DoubleWidth(exactly: source) else { - preconditionFailure("Value is outside the representable range") - } - self = result - } - - public init?(exactly source: T) { - // Can't represent a negative 'source' if Base is unsigned. - guard DoubleWidth.isSigned || source >= 0 else { return nil } - - // Is 'source' entirely representable in Low? - if let low = Low(exactly: source.magnitude) { - self.init(source < (0 as T) ? (~0, ~low &+ 1) : (0, low)) - } else { - // At this point we know source.bitWidth > Base.bitWidth, or else we - // would've taken the first branch. - let lowInT = source & T(~0 as Low) - let highInT = source >> Low.bitWidth - - let low = Low(lowInT) - guard let high = High(exactly: highInT) else { return nil } - self.init(high, low) - } - } -} - -#if false - -// This conformance is only possible once the type is in the stdlib, as it uses -// Builtin -extension DoubleWidth: _ExpressibleByBuiltinIntegerLiteral { - public init(_builtinIntegerLiteral _x: Builtin.IntegerLiteral) { - var _x = _x - self = DoubleWidth() - - // If we can capture the entire literal in a single Int64, stop there. - // This avoids some potential deep recursion due to literal expressions in - // other DoubleWidth methods. - let (_value, _overflow) = Builtin.s_to_s_checked_trunc_IntLiteral_Int64(_x) - if !Bool(_overflow) { - self = DoubleWidth(Int64(_value)) - return - } - - // Convert all but the most significant 64 bits as unsigned integers. - let _shift = Builtin.sext_Int64_IntLiteral((64 as Int64)._value) - let lowWordCount = (bitWidth - 1) / 64 - for i in 0..) { - // Multiples of word size only. - guard Base.bitWidth == Base.Magnitude.bitWidth && - (UInt.bitWidth % Base.bitWidth == 0 || - Base.bitWidth % UInt.bitWidth == 0) else { - fatalError("Access to words is not supported on this type") - } - self._high = value._storage.high.words - self._low = value._storage.low.words - assert(!_low.isEmpty) - } - } -} - -extension DoubleWidth.Words: RandomAccessCollection { - public typealias Index = Int - - public var startIndex: Index { - return 0 - } - - public var endIndex: Index { - return count - } - - public var count: Int { - if Base.bitWidth < UInt.bitWidth { return 1 } - return _low.count + _high.count - } - - public subscript(_ i: Index) -> UInt { - if Base.bitWidth < UInt.bitWidth { - precondition(i == 0, "Invalid index") - assert(2 * Base.bitWidth <= UInt.bitWidth) - return _low.first! | (_high.first! &<< Base.bitWidth._lowWord) - } - if i < _low.count { - return _low[i + _low.startIndex] - } - - return _high[i - _low.count + _high.startIndex] - } -} - -extension DoubleWidth : FixedWidthInteger { - public var words: Words { - return Words(self) - } - - public static var isSigned: Bool { - return Base.isSigned - } - - public static var max: DoubleWidth { - return self.init(High.max, Low.max) - } - - public static var min: DoubleWidth { - return self.init(High.min, Low.min) - } - - public static var bitWidth: Int { - return High.bitWidth + Low.bitWidth - } - - public func addingReportingOverflow(_ rhs: DoubleWidth) - -> (partialValue: DoubleWidth, overflow: Bool) { - let (low, lowOverflow) = - _storage.low.addingReportingOverflow(rhs._storage.low) - let (high, highOverflow) = - _storage.high.addingReportingOverflow(rhs._storage.high) - let result = (high &+ (lowOverflow ? 1 : 0), low) - let overflow = highOverflow || - high == Base.max && lowOverflow - return (partialValue: DoubleWidth(result), overflow: overflow) - } - - public func subtractingReportingOverflow(_ rhs: DoubleWidth) - -> (partialValue: DoubleWidth, overflow: Bool) { - let (low, lowOverflow) = - _storage.low.subtractingReportingOverflow(rhs._storage.low) - let (high, highOverflow) = - _storage.high.subtractingReportingOverflow(rhs._storage.high) - let result = (high &- (lowOverflow ? 1 : 0), low) - let overflow = highOverflow || - high == Base.min && lowOverflow - return (partialValue: DoubleWidth(result), overflow: overflow) - } - - public func multipliedReportingOverflow( - by rhs: DoubleWidth - ) -> (partialValue: DoubleWidth, overflow: Bool) { - let (carry, product) = multipliedFullWidth(by: rhs) - let result = DoubleWidth(truncatingIfNeeded: product) - - let isNegative = DoubleWidth.isSigned && - (self < (0 as DoubleWidth)) != (rhs < (0 as DoubleWidth)) - let didCarry = isNegative - ? carry != ~(0 as DoubleWidth) - : carry != (0 as DoubleWidth) - let hadPositiveOverflow = - DoubleWidth.isSigned && !isNegative && product.leadingZeroBitCount == 0 - - return (result, didCarry || hadPositiveOverflow) - } - - public func quotientAndRemainder( - dividingBy other: DoubleWidth - ) -> (quotient: DoubleWidth, remainder: DoubleWidth) { - let (quotient, remainder) = - Magnitude._divide(self.magnitude, by: other.magnitude) - guard DoubleWidth.isSigned else { - return (DoubleWidth(quotient), DoubleWidth(remainder)) - } - let isNegative = (self.high < (0 as High)) != (other.high < (0 as High)) - let quotient_ = isNegative - ? quotient == DoubleWidth.min.magnitude - ? DoubleWidth.min - : 0 - DoubleWidth(quotient) - : DoubleWidth(quotient) - let remainder_ = self.high < (0 as High) - ? 0 - DoubleWidth(remainder) - : DoubleWidth(remainder) - return (quotient_, remainder_) - } - - public func dividedReportingOverflow( - by other: DoubleWidth - ) -> (partialValue: DoubleWidth, overflow: Bool) { - if other == (0 as DoubleWidth) { return (self, true) } - if DoubleWidth.isSigned && other == -1 && self == .min { - return (self, true) - } - return (quotientAndRemainder(dividingBy: other).quotient, false) - } - - public func remainderReportingOverflow( - dividingBy other: DoubleWidth - ) -> (partialValue: DoubleWidth, overflow: Bool) { - if other == (0 as DoubleWidth) { return (self, true) } - if DoubleWidth.isSigned && other == -1 && self == .min { return (0, true) } - return (quotientAndRemainder(dividingBy: other).remainder, false) - } - - public func multipliedFullWidth( - by other: DoubleWidth - ) -> (high: DoubleWidth, low: DoubleWidth.Magnitude) { - let isNegative = DoubleWidth.isSigned && - (self < (0 as DoubleWidth)) != (other < (0 as DoubleWidth)) - - func mul(_ x: Low, _ y: Low) -> (partial: Low, carry: Low) { - let (high, low) = x.multipliedFullWidth(by: y) - return (low, high) - } - - func sum(_ x: Low, _ y: Low, _ z: Low) -> (partial: Low, carry: Low) { - let (sum1, overflow1) = x.addingReportingOverflow(y) - let (sum2, overflow2) = sum1.addingReportingOverflow(z) - let carry: Low = (overflow1 ? 1 : 0) + (overflow2 ? 1 : 0) - return (sum2, carry) - } - - let lhs = self.magnitude - let rhs = other.magnitude - - let a = mul(rhs._storage.low, lhs._storage.low) - let b = mul(rhs._storage.low, lhs._storage.high) - let c = mul(rhs._storage.high, lhs._storage.low) - let d = mul(rhs._storage.high, lhs._storage.high) - - let mid1 = sum(a.carry, b.partial, c.partial) - let mid2 = sum(b.carry, c.carry, d.partial) - - let low = - DoubleWidth(mid1.partial, a.partial) - let high = - DoubleWidth(High(mid2.carry + d.carry), mid1.carry + mid2.partial) - - if isNegative { - let (lowComplement, overflow) = (~low).addingReportingOverflow(1) - return (~high + (overflow ? 1 : 0 as DoubleWidth), lowComplement) - } else { - return (high, low) - } - } - - public func dividingFullWidth( - _ dividend: (high: DoubleWidth, low: DoubleWidth.Magnitude) - ) -> (quotient: DoubleWidth, remainder: DoubleWidth) { - let other = DoubleWidth(dividend) - let (quotient, remainder) = - Magnitude._divide(other.magnitude, by: self.magnitude) - guard DoubleWidth.isSigned else { - return (DoubleWidth(quotient), DoubleWidth(remainder)) - } - let isNegative = - (self.high < (0 as High)) != (other.high.high < (0 as High)) - let quotient_ = isNegative - ? quotient == DoubleWidth.min.magnitude - ? DoubleWidth.min - : 0 - DoubleWidth(quotient) - : DoubleWidth(quotient) - let remainder_ = other.high.high < (0 as High) - ? 0 - DoubleWidth(remainder) - : DoubleWidth(remainder) - return (quotient_, remainder_) - } - - public static func &=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - lhs._storage.low &= rhs._storage.low - lhs._storage.high &= rhs._storage.high - } - - public static func |=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - lhs._storage.low |= rhs._storage.low - lhs._storage.high |= rhs._storage.high - } - - public static func ^=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - lhs._storage.low ^= rhs._storage.low - lhs._storage.high ^= rhs._storage.high - } - - public static func <<=(lhs: inout DoubleWidth, rhs: DoubleWidth) { - if DoubleWidth.isSigned && rhs < (0 as DoubleWidth) { - lhs >>= 0 - rhs - return - } - - // Shift is larger than this type's bit width. - if rhs._storage.high != (0 as High) || - rhs._storage.low >= DoubleWidth.bitWidth - { - lhs = 0 - return - } - - lhs &<<= rhs - } - - public static func >>=(lhs: inout DoubleWidth, rhs: DoubleWidth) { - if DoubleWidth.isSigned && rhs < (0 as DoubleWidth) { - lhs <<= 0 - rhs - return - } - - // Shift is larger than this type's bit width. - if rhs._storage.high != (0 as High) || - rhs._storage.low >= DoubleWidth.bitWidth - { - lhs = lhs < (0 as DoubleWidth) ? ~0 : 0 - return - } - - lhs &>>= rhs - } - - /// Returns this value "masked" by its bit width. - /// - /// "Masking" notionally involves repeatedly incrementing or decrementing this - /// value by `self.bitWidth` until the result is contained in the range - /// `0.. DoubleWidth { - // FIXME(integers): test types with bit widths that aren't powers of 2 - if DoubleWidth.bitWidth.nonzeroBitCount == 1 { - return self & DoubleWidth(DoubleWidth.bitWidth &- 1) - } - if DoubleWidth.isSigned && self._storage.high < (0 as High) { - return self % DoubleWidth(DoubleWidth.bitWidth) + self - } - return self % DoubleWidth(DoubleWidth.bitWidth) - } - - public static func &<<=(lhs: inout DoubleWidth, rhs: DoubleWidth) { - let rhs = rhs._masked() - - guard rhs._storage.low < Base.bitWidth else { - lhs._storage.high = High( - truncatingIfNeeded: lhs._storage.low &<< - (rhs._storage.low &- Low(Base.bitWidth))) - lhs._storage.low = 0 - return - } - - guard rhs._storage.low != (0 as Low) else { return } - lhs._storage.high &<<= High(rhs._storage.low) - lhs._storage.high |= High( - truncatingIfNeeded: lhs._storage.low &>> - (Low(Base.bitWidth) &- rhs._storage.low)) - lhs._storage.low &<<= rhs._storage.low - } - - public static func &>>=(lhs: inout DoubleWidth, rhs: DoubleWidth) { - let rhs = rhs._masked() - - guard rhs._storage.low < Base.bitWidth else { - lhs._storage.low = Low( - truncatingIfNeeded: lhs._storage.high &>> - High(rhs._storage.low &- Low(Base.bitWidth))) - lhs._storage.high = lhs._storage.high < (0 as High) ? ~0 : 0 - return - } - - guard rhs._storage.low != (0 as Low) else { return } - lhs._storage.low &>>= rhs._storage.low - lhs._storage.low |= Low( - truncatingIfNeeded: lhs._storage.high &<< - High(Low(Base.bitWidth) &- rhs._storage.low)) - lhs._storage.high &>>= High(rhs._storage.low) - } - - // FIXME(integers): remove this once the operators are back to Numeric - public static func + ( - lhs: DoubleWidth, rhs: DoubleWidth - ) -> DoubleWidth { - var lhs = lhs - lhs += rhs - return lhs - } - - public static func +=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - let (result, overflow) = lhs.addingReportingOverflow(rhs) - precondition(!overflow, "Overflow in +=") - lhs = result - } - - // FIXME(integers): remove this once the operators are back to Numeric - public static func - ( - lhs: DoubleWidth, rhs: DoubleWidth - ) -> DoubleWidth { - var lhs = lhs - lhs -= rhs - return lhs - } - - public static func -=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - let (result, overflow) = lhs.subtractingReportingOverflow(rhs) - precondition(!overflow, "Overflow in -=") - lhs = result - } - - // FIXME(integers): remove this once the operators are back to Numeric - public static func * ( - lhs: DoubleWidth, rhs: DoubleWidth - ) -> DoubleWidth { - var lhs = lhs - lhs *= rhs - return lhs - } - - public static func *=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - let (result, overflow) = lhs.multipliedReportingOverflow(by:rhs) - precondition(!overflow, "Overflow in *=") - lhs = result - } - - // FIXME(integers): remove this once the operators are back to Numeric - public static func / ( - lhs: DoubleWidth, rhs: DoubleWidth - ) -> DoubleWidth { - var lhs = lhs - lhs /= rhs - return lhs - } - - public static func /=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - let (result, overflow) = lhs.dividedReportingOverflow(by:rhs) - precondition(!overflow, "Overflow in /=") - lhs = result - } - - // FIXME(integers): remove this once the operators are back to Numeric - public static func % ( - lhs: DoubleWidth, rhs: DoubleWidth - ) -> DoubleWidth { - var lhs = lhs - lhs %= rhs - return lhs - } - - public static func %=( - lhs: inout DoubleWidth, rhs: DoubleWidth - ) { - let (result, overflow) = lhs.remainderReportingOverflow(dividingBy:rhs) - precondition(!overflow, "Overflow in %=") - lhs = result - } - - public init(_truncatingBits bits: UInt) { - _storage.low = Low(_truncatingBits: bits) - _storage.high = High(_truncatingBits: bits >> UInt(Low.bitWidth)) - } - - public init(integerLiteral x: Int) { - self.init(x) - } - public var leadingZeroBitCount: Int { - return high == (0 as High) - ? High.bitWidth + low.leadingZeroBitCount - : high.leadingZeroBitCount - } - - public var trailingZeroBitCount: Int { - return low == (0 as Low) - ? Low.bitWidth + high.trailingZeroBitCount - : low.trailingZeroBitCount - } - - public var nonzeroBitCount: Int { - return high.nonzeroBitCount + low.nonzeroBitCount - } - - public var byteSwapped: DoubleWidth { - return DoubleWidth( - High(truncatingIfNeeded: low.byteSwapped), - Low(truncatingIfNeeded: high.byteSwapped)) - } -} - -extension DoubleWidth : UnsignedInteger where Base : UnsignedInteger { - /// Returns the quotient and remainder after dividing a triple-width magnitude - /// `lhs` by a double-width magnitude `rhs`. - /// - /// This operation is conceptually that described by Burnikel and Ziegler - /// (1998). - internal static func _divide( - _ lhs: (high: Low, mid: Low, low: Low), by rhs: Magnitude - ) -> (quotient: Low, remainder: Magnitude) { - // The following invariants are guaranteed to hold by dividingFullWidth or - // quotientAndRemainder before this method is invoked: - assert(lhs.high != (0 as Low)) - assert(rhs.leadingZeroBitCount == 0) - assert(Magnitude(lhs.high, lhs.mid) < rhs) - - // Estimate the quotient. - var quotient = lhs.high == rhs.high - ? Low.max - : rhs.high.dividingFullWidth((lhs.high, lhs.mid)).quotient - // Compute quotient * rhs. - // TODO: This could be performed more efficiently. - var product = - DoubleWidth( - 0, Magnitude(quotient.multipliedFullWidth(by: rhs.low))) - let (x, y) = quotient.multipliedFullWidth(by: rhs.high) - product += DoubleWidth(Magnitude(0, x), Magnitude(y, 0)) - // Compute the remainder after decrementing quotient as necessary. - var remainder = - DoubleWidth( - Magnitude(0, lhs.high), Magnitude(lhs.mid, lhs.low)) - while remainder < product { - quotient = quotient &- 1 - remainder += DoubleWidth(0, rhs) - } - remainder -= product - - return (quotient, remainder.low) - } - - /// Returns the quotient and remainder after dividing a quadruple-width - /// magnitude `lhs` by a double-width magnitude `rhs`. - internal static func _divide( - _ lhs: DoubleWidth, by rhs: Magnitude - ) -> (quotient: Magnitude, remainder: Magnitude) { - guard _fastPath(rhs > (0 as Magnitude)) else { - fatalError("Division by zero") - } - guard _fastPath(rhs >= lhs.high) else { - fatalError("Division results in an overflow") - } - - if lhs.high == (0 as Magnitude) { - return lhs.low.quotientAndRemainder(dividingBy: rhs) - } - - if rhs.high == (0 as Low) { - let a = lhs.high.high % rhs.low - let b = a == (0 as Low) - ? lhs.high.low % rhs.low - : rhs.low.dividingFullWidth((a, lhs.high.low)).remainder - let (x, c) = b == (0 as Low) - ? lhs.low.high.quotientAndRemainder(dividingBy: rhs.low) - : rhs.low.dividingFullWidth((b, lhs.low.high)) - let (y, d) = c == (0 as Low) - ? lhs.low.low.quotientAndRemainder(dividingBy: rhs.low) - : rhs.low.dividingFullWidth((c, lhs.low.low)) - return (Magnitude(x, y), Magnitude(0, d)) - } - - // Left shift both rhs and lhs, then divide and right shift the remainder. - let shift = rhs.leadingZeroBitCount - let rhs = rhs &<< shift - let lhs = lhs &<< shift - if lhs.high.high == (0 as Low) - && Magnitude(lhs.high.low, lhs.low.high) < rhs { - let (quotient, remainder) = - Magnitude._divide((lhs.high.low, lhs.low.high, lhs.low.low), by: rhs) - return (Magnitude(0, quotient), remainder &>> shift) - } - let (x, a) = - Magnitude._divide((lhs.high.high, lhs.high.low, lhs.low.high), by: rhs) - let (y, b) = - Magnitude._divide((a.high, a.low, lhs.low.low), by: rhs) - return (Magnitude(x, y), b &>> shift) - } - - /// Returns the quotient and remainder after dividing a double-width - /// magnitude `lhs` by a double-width magnitude `rhs`. - internal static func _divide( - _ lhs: Magnitude, by rhs: Magnitude - ) -> (quotient: Magnitude, remainder: Magnitude) { - guard _fastPath(rhs > (0 as Magnitude)) else { - fatalError("Division by zero") - } - guard rhs < lhs else { - if _fastPath(rhs > lhs) { return (0, lhs) } - return (1, 0) - } - - if lhs.high == (0 as Low) { - let (quotient, remainder) = - lhs.low.quotientAndRemainder(dividingBy: rhs.low) - return (Magnitude(quotient), Magnitude(remainder)) - } - - if rhs.high == (0 as Low) { - let (x, a) = lhs.high.quotientAndRemainder(dividingBy: rhs.low) - let (y, b) = a == (0 as Low) - ? lhs.low.quotientAndRemainder(dividingBy: rhs.low) - : rhs.low.dividingFullWidth((a, lhs.low)) - return (Magnitude(x, y), Magnitude(0, b)) - } - - // Left shift both rhs and lhs, then divide and right shift the remainder. - let shift = rhs.leadingZeroBitCount - let rhs = rhs &<< shift - let high = (lhs &>> (Magnitude.bitWidth &- shift)).low - let lhs = lhs &<< shift - let (quotient, remainder) = - Magnitude._divide((high, lhs.high, lhs.low), by: rhs) - return (Magnitude(0, quotient), remainder &>> shift) - } -} - -extension DoubleWidth : SignedNumeric, SignedInteger - where Base : SignedInteger {} diff --git a/Sources/ScaleCodec/BigIntegers.swift b/Sources/ScaleCodec/BigIntegers.swift deleted file mode 100644 index cb6818e..0000000 --- a/Sources/ScaleCodec/BigIntegers.swift +++ /dev/null @@ -1,31 +0,0 @@ -// -// BigIntegers.swift -// -// -// Created by Yehor Popovych on 10/6/20. -// - -import Foundation -#if !COCOAPODS -@_exported import DoubleWidth -#endif - -// This part uses DoubleWidth from Apple Swift stdlib prototypes. -// Nested types will have performance drop, so avoid using them if not needed. -// Int128/UInt128 should be good. Int1024/UInt1024 is really slow. - -public typealias Int128 = DoubleWidth -public typealias Int256 = DoubleWidth -public typealias Int512 = DoubleWidth -public typealias Int1024 = DoubleWidth - -public typealias UInt128 = DoubleWidth -public typealias UInt256 = DoubleWidth -public typealias UInt512 = DoubleWidth -public typealias UInt1024 = DoubleWidth - -extension DoubleWidth: CompactCodable where Base: UnsignedInteger {} -extension DoubleWidth: CompactConvertible where Base: UnsignedInteger {} - -extension DoubleWidth: FixedDataCodable, DataConvertible, SizeCalculable {} - diff --git a/Tests/DoubleWidthTests/DoubleWidthTests.swift b/Tests/DoubleWidthTests/DoubleWidthTests.swift deleted file mode 100644 index 618882b..0000000 --- a/Tests/DoubleWidthTests/DoubleWidthTests.swift +++ /dev/null @@ -1,278 +0,0 @@ -// -// DoubleWidthTests.swift -// -// -// Created by Yehor Popovych on 1/8/23. -// - -import XCTest -@testable import ScaleCodec - -final class DoubleWidthTests: XCTestCase { - func testArithmetic_unsigned() { - let x: DoubleWidth = 1000 - let y: DoubleWidth = 1111 - XCTAssertEqual(x + 1, 1001) - XCTAssertEqual(x + x, 2000) - XCTAssertEqual(x - (1 as DoubleWidth), 999) - XCTAssertEqual(x - x, 0) - XCTAssertEqual(y - x, 111) - - XCTAssertEqual(x * 7, 7000) - XCTAssertEqual(y * 7, 7777) - - XCTAssertEqual(x / 3, 333) - XCTAssertEqual(x / x, 1) - XCTAssertEqual(x / y, 0) - XCTAssertEqual(y / x, 1) - - XCTAssertEqual(x % 3, 1) - XCTAssertEqual(x % y, x) - } - - func testArithmetic_signed() { - let x: DoubleWidth = 1000 - let y: DoubleWidth = -1111 - XCTAssertEqual(x + 1, 1001) - XCTAssertEqual(x + x, 2000) - XCTAssertEqual(x - (1 as DoubleWidth), 999) - XCTAssertEqual(x - x, 0) - XCTAssertEqual(0 - x, -1000) - XCTAssertEqual(x + y, -111) - XCTAssertEqual(x - y, 2111) - - XCTAssertEqual(x * 7, 7000) - XCTAssertEqual(y * 7, -7777) - XCTAssertEqual(x * -7, -7000) - XCTAssertEqual(y * -7, 7777) - - XCTAssertEqual(x / 3, 333) - XCTAssertEqual(x / -3, -333) - XCTAssertEqual(x / x, 1) - XCTAssertEqual(x / y, 0) - XCTAssertEqual(y / x, -1) - XCTAssertEqual(y / y, 1) - - XCTAssertEqual(x % 3, 1) - XCTAssertEqual(x % -3, 1) - XCTAssertEqual(y % 3, -1) - XCTAssertEqual(y % -3, -1) - - XCTAssertEqual(-y, 1111) - XCTAssertEqual(-x, -1000) - } - - func testNested() { - do { - let x = UInt1024.max - let (y, o) = x.addingReportingOverflow(1) - XCTAssertEqual(y, 0) - XCTAssertTrue(y == (0 as Int)) - XCTAssertTrue(o) - } - - do { - let x = Int1024.max - let (y, o) = x.addingReportingOverflow(1) - XCTAssertEqual(y, Int1024.min) - XCTAssertTrue(y < 0) - XCTAssertTrue(y < (0 as Int)) - XCTAssertTrue(y < (0 as UInt)) - XCTAssertTrue(o) - } - - XCTAssertFalse(UInt1024.isSigned) - XCTAssertEqual(UInt1024.bitWidth, 1024) - XCTAssertTrue(Int1024.isSigned) - XCTAssertEqual(Int1024.bitWidth, 1024) - - XCTAssertEqual( - Array(UInt1024.max.words), Array(repeatElement(UInt.max, count: 1024 / UInt.bitWidth))) - } - - func testinits() { - typealias DWU16 = DoubleWidth - - XCTAssertTrue(DWU16(UInt16.max) == UInt16.max) - XCTAssertNil(DWU16(exactly: UInt32.max)) - XCTAssertEqual(DWU16(truncatingIfNeeded: UInt64.max), DWU16.max) - } - - func testMagnitude() { - typealias DWU16 = DoubleWidth - typealias DWI16 = DoubleWidth - - XCTAssertTrue(DWU16.min.magnitude == UInt16.min.magnitude) - XCTAssertTrue((42 as DWU16).magnitude == (42 as UInt16).magnitude) - XCTAssertTrue(DWU16.max.magnitude == UInt16.max.magnitude) - - XCTAssertTrue(DWI16.min.magnitude == Int16.min.magnitude) - XCTAssertTrue((-42 as DWI16).magnitude == (-42 as Int16).magnitude) - XCTAssertTrue(DWI16().magnitude == Int16(0).magnitude) // See https://github.com/apple/swift/issues/49152. - XCTAssertTrue((42 as DWI16).magnitude == (42 as Int16).magnitude) - XCTAssertTrue(DWI16.max.magnitude == Int16.max.magnitude) - } - - func testTwoWords() { - typealias DW = DoubleWidth - - XCTAssertEqual(-1 as DW, DW(truncatingIfNeeded: -1 as Int8)) - - XCTAssertNil(Int(exactly: DW(Int.min) - 1)) - XCTAssertNil(Int(exactly: DW(Int.max) + 1)) - - XCTAssertTrue(DW(Int.min) - 1 < Int.min) - XCTAssertTrue(DW(Int.max) + 1 > Int.max) - } - - func testBitshifts() { - typealias DWU64 = DoubleWidth>> - typealias DWI64 = DoubleWidth>> - - func f(_ x: T, type: U.Type) { - let y = U(x) - XCTAssertEqual(T.bitWidth, U.bitWidth) - for i in -(T.bitWidth + 1)...(T.bitWidth + 1) { - XCTAssertTrue(x << i == y << i) - XCTAssertTrue(x >> i == y >> i) - - XCTAssertTrue(x &<< i == y &<< i) - XCTAssertTrue(x &>> i == y &>> i) - } - } - - f(1 as UInt64, type: DWU64.self) - f(~(~0 as UInt64 >> 1), type: DWU64.self) - f(UInt64.max, type: DWU64.self) - // 0b01010101_10100101_11110000_10100101_11110000_10100101_11110000_10100101 - f(17340530535757639845 as UInt64, type: DWU64.self) - - f(1 as Int64, type: DWI64.self) - f(Int64.min, type: DWI64.self) - f(Int64.max, type: DWI64.self) - // 0b01010101_10100101_11110000_10100101_11110000_10100101_11110000_10100101 - f(6171603459878809765 as Int64, type: DWI64.self) - } - - func testRemainderReportingOverflow_DividingByMinusOne() { - func f(_ x: Int256, _ y: Int256) -> Int256 { - return x.remainderReportingOverflow(dividingBy: y).partialValue - } - XCTAssertEqual(f(.max, -1), 0) - XCTAssertEqual(f(.min, -1), 0) - } - - func testisMultiple() { - func isMultipleTest(type: T.Type) { - XCTAssertTrue(T.min.isMultiple(of: 2)) - XCTAssertFalse(T.max.isMultiple(of: 10)) - // Test that these do not crash. - XCTAssertTrue((0 as T).isMultiple(of: 0)) - XCTAssertFalse((1 as T).isMultiple(of: 0)) - XCTAssertTrue(T.min.isMultiple(of: 0 &- 1)) - } - isMultipleTest(type: Int128.self) - isMultipleTest(type: UInt128.self) - } - - typealias DWI16 = DoubleWidth - typealias DWU16 = DoubleWidth - - func testConversions() { - XCTAssertTrue(DWI16(1 << 15 - 1) == Int(1 << 15 - 1)) - XCTAssertTrue(DWI16(-1 << 15) == Int(-1 << 15)) - XCTAssertTrue(DWU16(1 << 16 - 1) == Int(1 << 16 - 1)) - XCTAssertTrue(DWU16(0) == Int(0)) - - XCTAssertTrue(DWI16(Double(1 << 15 - 1)) == Int(1 << 15 - 1)) - XCTAssertTrue(DWI16(Double(-1 << 15)) == Int(-1 << 15)) - XCTAssertTrue(DWU16(Double(1 << 16 - 1)) == Int(1 << 16 - 1)) - XCTAssertTrue(DWU16(Double(0)) == Int(0)) - - XCTAssertTrue(DWI16(Double(1 << 15 - 1) + 0.9) == Int(1 << 15 - 1)) - XCTAssertTrue(DWI16(Double(-1 << 15) - 0.9) == Int(-1 << 15)) - XCTAssertTrue(DWU16(Double(1 << 16 - 1) + 0.9) == Int(1 << 16 - 1)) - XCTAssertTrue(DWU16(Double(0) - 0.9) == Int(0)) - - XCTAssertEqual(DWI16(0.00001), 0) - XCTAssertEqual(DWU16(0.00001), 0) - } - - func testExact_Conversions() { - XCTAssertEqual(DWI16(Double(1 << 15 - 1)), DWI16(exactly: Double(1 << 15 - 1))!) - XCTAssertEqual(DWI16(Double(-1 << 15)), DWI16(exactly: Double(-1 << 15))!) - XCTAssertEqual(DWU16(Double(1 << 16 - 1)), DWU16(exactly: Double(1 << 16 - 1))!) - XCTAssertEqual(DWU16(Double(0)), DWU16(exactly: Double(0))!) - - XCTAssertNil(DWI16(exactly: Double(1 << 15 - 1) + 0.9)) - XCTAssertNil(DWI16(exactly: Double(-1 << 15) - 0.9)) - XCTAssertNil(DWU16(exactly: Double(1 << 16 - 1) + 0.9)) - XCTAssertNil(DWU16(exactly: Double(0) - 0.9)) - - XCTAssertNil(DWI16(exactly: Double(1 << 15))) - XCTAssertNil(DWI16(exactly: Double(-1 << 15) - 1)) - XCTAssertNil(DWU16(exactly: Double(1 << 16))) - XCTAssertNil(DWU16(exactly: Double(-1))) - - XCTAssertNil(DWI16(exactly: 0.00001)) - XCTAssertNil(DWU16(exactly: 0.00001)) - - XCTAssertNil(DWU16(exactly: Double.nan)) - XCTAssertNil(DWU16(exactly: Float.nan)) - XCTAssertNil(DWU16(exactly: Double.infinity)) - XCTAssertNil(DWU16(exactly: Float.infinity)) - } - - func testConversions_String() { - XCTAssertEqual(String(Int256.max, radix: 16), - "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff") - XCTAssertEqual(String(Int256.min, radix: 16), - "-8000000000000000000000000000000000000000000000000000000000000000") - - XCTAssertEqual(String(Int256.max, radix: 2), """ - 1111111111111111111111111111111111111111111111111111111111111111\ - 1111111111111111111111111111111111111111111111111111111111111111\ - 1111111111111111111111111111111111111111111111111111111111111111\ - 111111111111111111111111111111111111111111111111111111111111111 - """) - XCTAssertEqual(String(Int256.min, radix: 2), """ - -100000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 0000000000000000000000000000000000000000000000000000000000000000\ - 00000000000000000000000000000000000000000000000000000000000000000 - """) - - XCTAssertEqual(String(Int128.max, radix: 10), - "170141183460469231731687303715884105727") - XCTAssertEqual(String(Int128.min, radix: 10), - "-170141183460469231731687303715884105728") - } - - func testWords() { - XCTAssertEqual(Array((0 as DoubleWidth).words), [0]) - XCTAssertEqual(Array((1 as DoubleWidth).words), [1]) - XCTAssertEqual(Array((-1 as DoubleWidth).words), [UInt.max]) - XCTAssertEqual(Array((256 as DoubleWidth).words), [256]) - XCTAssertEqual(Array((-256 as DoubleWidth).words), [UInt.max - 255]) - XCTAssertEqual(Array(DoubleWidth.max.words), [32767]) - XCTAssertEqual(Array(DoubleWidth.min.words), [UInt.max - 32767]) - - XCTAssertEqual(Array((0 as Int1024).words), - Array(repeatElement(0 as UInt, count: 1024 / UInt.bitWidth))) - XCTAssertEqual(Array((-1 as Int1024).words), - Array(repeatElement(UInt.max, count: 1024 / UInt.bitWidth))) - XCTAssertEqual(Array((1 as Int1024).words), - [1] + Array(repeating: 0, count: 1024 / UInt.bitWidth - 1)) - } - - func testConditional_Conformance() { - checkSignedIntegerConformance(0 as Int128) - checkSignedIntegerConformance(0 as Int1024) - - checkUnsignedIntegerConformance(0 as UInt128) - checkUnsignedIntegerConformance(0 as UInt1024) - } - - func checkSignedIntegerConformance(_ x: T) {} - func checkUnsignedIntegerConformance(_ x: T) {} -} diff --git a/Tests/ScaleCodecTests/CompactTests.swift b/Tests/ScaleCodecTests/CompactTests.swift index cade6af..508ab33 100644 --- a/Tests/ScaleCodecTests/CompactTests.swift +++ b/Tests/ScaleCodecTests/CompactTests.swift @@ -26,18 +26,6 @@ final class CompactTests: XCTestCase { runTests(uint64Values(UInt64.self)) } - func testUInt128() { - runTests(uint128Values(UInt128.self)) - } - - func testUInt1024() { - let tests = uint128Values(UInt1024.self) + [ - (UInt1024.compactMax, Data(repeating: 0xff, count: 68).hex) - ] - runTests(tests) - XCTAssertThrowsError(try ScaleCodec.encode(UInt1024(1) << 537, .compact)) - } - func testTopLevelAPI() { do { let enc = try ScaleCodec.encode(UInt32.max, .compact) @@ -86,15 +74,4 @@ final class CompactTests: XCTestCase { (T(UInt64.max), "13 ff ff ff ff ff ff ff ff") ] } - - func uint128Values(_ type: T.Type) -> [(T, String)] { - return uint64Values(type) + [ - (T(UInt128(1) << 64), "17 00 00 00 00 00 00 00 00 01"), - (T(UInt128(1) << 72 - 1), "17 ff ff ff ff ff ff ff ff ff"), - (T(UInt128(1) << 72), "1b 00 00 00 00 00 00 00 00 00 01"), - (T(UInt128(1) << 80 - 1), "1b ff ff ff ff ff ff ff ff ff ff"), - (T(UInt128(1) << 120), "33 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01"), - (T(UInt128.max), "33 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff") - ] - } } diff --git a/Tests/ScaleCodecTests/IntegerTests.swift b/Tests/ScaleCodecTests/IntegerTests.swift index f4255c3..8f35cbc 100644 --- a/Tests/ScaleCodecTests/IntegerTests.swift +++ b/Tests/ScaleCodecTests/IntegerTests.swift @@ -87,57 +87,6 @@ final class IntegerTests: XCTestCase { RunEncDecTests(tests) } - func testInt128() { - let tests = intValues( - max: Int128.max, - min: Int128.min, - bytes: Int128.bitWidth / 8 - ) - RunEncDecTests(tests) - } - - func testUInt128() { - let tests = uintValues( - max: UInt128.max, - bytes: UInt128.bitWidth / 8 - ) - RunEncDecTests(tests) - } - - func testInt256() { - let tests = intValues( - max: Int256.max, - min: Int256.min, - bytes: Int256.bitWidth / 8 - ) - RunEncDecTests(tests) - } - - func testUInt256() { - let tests = uintValues( - max: UInt256.max, - bytes: UInt256.bitWidth / 8 - ) - RunEncDecTests(tests) - } - - func testInt512() { - let tests = intValues( - max: Int512.max, - min: Int512.min, - bytes: Int512.bitWidth / 8 - ) - RunEncDecTests(tests) - } - - func testUInt512() { - let tests = uintValues( - max: UInt512.max, - bytes: UInt512.bitWidth / 8 - ) - RunEncDecTests(tests) - } - func uintValues(max: T, bytes: Int) -> [(T, String)] { let z = Data(repeating: 0x00, count: bytes) let m = Data(repeating: 0xff, count: bytes) diff --git a/Tests/ScaleCodecTests/OptionalTests.swift b/Tests/ScaleCodecTests/OptionalTests.swift index 32b0143..0b63d72 100644 --- a/Tests/ScaleCodecTests/OptionalTests.swift +++ b/Tests/ScaleCodecTests/OptionalTests.swift @@ -81,7 +81,7 @@ final class OptionalTests: XCTestCase { let tests: [(TDataEnum?, String)] = [ (nil, "00"), (.c1(-128), "01 \(try ScaleCodec.encode(TDataEnum.c1(-128)).hex)"), - (.c2(UInt1024.compactMax), "01 \(try ScaleCodec.encode(TDataEnum.c2(UInt1024.compactMax)).hex)"), + (.c2(UInt64.compactMax), "01 \(try ScaleCodec.encode(TDataEnum.c2(UInt64.compactMax)).hex)"), (.c3(.c2), "01 \(try ScaleCodec.encode(TDataEnum.c3(.c2)).hex)") ] RunEncDecTests(tests) @@ -120,7 +120,7 @@ private enum TEnum: CaseIterable, Codable { private enum TDataEnum: Codable, Equatable { case c1(Int32) - case c2(UInt1024) + case c2(UInt64) case c3(TEnum) init(from decoder: inout D) throws { diff --git a/Tests/ScaleCodecTests/StructTests.swift b/Tests/ScaleCodecTests/StructTests.swift index 9c6ae98..7a7c458 100644 --- a/Tests/ScaleCodecTests/StructTests.swift +++ b/Tests/ScaleCodecTests/StructTests.swift @@ -31,32 +31,28 @@ final class StructTests: XCTestCase { func testComplexStuct() { let strct1 = ComplexStruct( i8: Int8.min, i16: Int16.min, i32: Int32.min, u32: UInt32.max, i64: Int64.min, - u64: UInt64.max, i128: Int128.min, u128: UInt128.max, - c8: UInt8.max, c16: UInt16.max, c64: UInt64.max, cb: UInt1024(UInt128.max), + u64: UInt64.max, c8: UInt8.max, c16: UInt16.max, c64: UInt64.max, enm: .c1("Hello"), earr: [.c1(nil), .c2(Int32.min, false)], carrarr: [[0], [UInt32.max, 0, UInt32.max], []], strct: SimpleStruct(("Hello", Int32.max), "World!") ) let encoded1 = """ - 80 00 80 00 00 00 80 ff ff ff ff 00 00 00 00 00 00 00 80 ff ff ff ff ff ff ff ff 00 00 \ - 00 00 00 00 00 00 00 00 00 00 00 00 00 80 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff \ - ff fd 03 fe ff 03 00 13 ff ff ff ff ff ff ff ff 33 ff ff ff ff ff ff ff ff ff ff ff ff \ - ff ff ff ff 00 01 14 48 65 6c 6c 6f 08 00 00 01 00 00 00 80 02 0c 04 00 0c 03 ff ff ff \ - ff 00 03 ff ff ff ff 00 01 14 48 65 6c 6c 6f 01 ff ff ff 7f 18 57 6f 72 6c 64 21 + 80 00 80 00 00 00 80 ff ff ff ff 00 00 00 00 00 00 00 80 ff ff ff ff ff ff ff ff fd 03 \ + fe ff 03 00 13 ff ff ff ff ff ff ff ff 00 01 14 48 65 6c 6c 6f 08 00 00 01 00 00 00 80 \ + 02 0c 04 00 0c 03 ff ff ff ff 00 03 ff ff ff ff 00 01 14 48 65 6c 6c 6f 01 ff ff ff 7f \ + 18 57 6f 72 6c 64 21 """ let strct2 = ComplexStruct( i8: Int8.max, i16: Int16.max, i32: Int32.max, u32: 0, i64: Int64.max, - u64: 0, i128: Int128.max, u128: 0, - c8: 0, c16: 0, c64: 0, cb: 0, + u64: 0, c8: 0, c16: 0, c64: 0, enm: .c1(nil), earr: [.c1("Hello"), .c2(Int32.max, nil)], carrarr: [[0, UInt32.max], [UInt32.max]], strct: SimpleStruct((nil, Int32.min), "") ) let encoded2 = """ - 7f ff 7f ff ff ff 7f 00 00 00 00 ff ff ff ff ff ff ff 7f 00 00 00 00 00 00 00 00 ff ff \ - ff ff ff ff ff ff ff ff ff ff ff ff ff 7f 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 \ - 00 00 00 00 00 00 00 08 00 01 14 48 65 6c 6c 6f 01 ff ff ff 7f 00 08 08 00 03 ff ff ff \ - ff 04 03 ff ff ff ff 00 01 00 00 00 80 00 + 7f ff 7f ff ff ff 7f 00 00 00 00 ff ff ff ff ff ff ff 7f 00 00 00 00 00 00 00 00 00 00 \ + 00 00 00 08 00 01 14 48 65 6c 6c 6f 01 ff ff ff 7f 00 08 08 00 03 ff ff ff ff 04 03 ff \ + ff ff ff 00 01 00 00 00 80 00 """ RunEncDecTests([(strct1, encoded1), (strct2, encoded2)]) } @@ -69,25 +65,22 @@ private struct ComplexStruct: Equatable, Codable { let u32: UInt32 let i64: Int64 let u64: UInt64 - let i128: Int128 - let u128: UInt128 let c8: UInt8 let c16: UInt16 let c64: UInt64 - let cb: UInt1024 let enm: TDataEnum let earr: Array let carrarr: Array> let strct: SimpleStruct init( - i8: Int8, i16: Int16, i32: Int32, u32: UInt32, i64: Int64, u64: UInt64, i128: Int128, - u128: UInt128, c8: UInt8, c16: UInt16, c64: UInt64, cb: UInt1024, enm: TDataEnum, + i8: Int8, i16: Int16, i32: Int32, u32: UInt32, i64: Int64, u64: UInt64, + c8: UInt8, c16: UInt16, c64: UInt64, enm: TDataEnum, earr: Array, carrarr: Array>, strct: SimpleStruct ) { self.i8 = i8; self.i16 = i16; self.i32 = i32; self.u32 = u32; self.i64 = i64 - self.u64 = u64; self.i128 = i128; self.u128 = u128; self.c8 = c8; self.c16 = c16 - self.c64 = c64; self.cb = cb; self.enm = enm; self.earr = earr + self.u64 = u64; self.c8 = c8; self.c16 = c16 + self.c64 = c64; self.enm = enm; self.earr = earr self.carrarr = carrarr; self.strct = strct } @@ -95,9 +88,8 @@ private struct ComplexStruct: Equatable, Codable { i8 = try decoder.decode(); i16 = try decoder.decode() i32 = try decoder.decode(); u32 = try decoder.decode() i64 = try decoder.decode(); u64 = try decoder.decode() - i128 = try decoder.decode(); u128 = try decoder.decode() c8 = try decoder.decode(.compact); c16 = try decoder.decode(.compact) - c64 = try decoder.decode(.compact); cb = try decoder.decode(.compact) + c64 = try decoder.decode(.compact); enm = try decoder.decode(); earr = try decoder.decode() let sarr = try decoder.decode(Array>>.self) carrarr = sarr.map { $0.map { $0.value } } @@ -112,12 +104,9 @@ private struct ComplexStruct: Equatable, Codable { try encoder.encode(u32) try encoder.encode(i64) try encoder.encode(u64) - try encoder.encode(i128) - try encoder.encode(u128) try encoder.encode(c8, .compact) try encoder.encode(c16, .compact) try encoder.encode(c64, .compact) - try encoder.encode(cb, .compact) try encoder.encode(enm) try encoder.encode(earr) try encoder.encode(sarr)