So I got rid of the old UInt72
code and added a stump version in the test file, like @xnw suggested.
struct UInt72: CustomDebugStringConvertible, FixedWidthInteger, UnsignedInteger {
// Implementation properties
var high: UInt8
var low: UInt64
// Main initializer
init(highOrderBits hi: UInt8, lowOrderBits lo: UInt64) { (high, low) = (hi, lo) }
// CustomDebugStringConvertible interface
var debugDescription: String { return "UInt72(\(high.fullHexadecimalString),\(low.fullHexadecimalString))" }
// FixedWidthInteger secret initializer
init(_truncatingBits bits: UInt) { self.init(highOrderBits: 0, lowOrderBits: UInt64(bits)) }
// FixedWidthInteger properties
var byteSwapped: UInt72 {
return UInt72(highOrderBits: UInt8(truncatingIfNeeded: low), lowOrderBits: (low.byteSwapped << 8) | UInt64(high))
}
var leadingZeroBitCount: Int { return high != 0 ? high.leadingZeroBitCount : 8 + low.leadingZeroBitCount }
var nonzeroBitCount: Int { return high.nonzeroBitCount + low.nonzeroBitCount }
static var bitWidth: Int { return 72 }
// BinaryInteger properties
var trailingZeroBitCount: Int { return low != 0 ? low.trailingZeroBitCount : high.trailingZeroBitCount + 64 }
var words: [UInt] { return Array(low.words) + high.words }
// ExpressibleByIntegerLiteral and Hashable support
init(integerLiteral value: UInt) { self.init(_truncatingBits: value) }
var hashValue: Int { return debugDescription.hashValue }
// BinaryInteger floating-point initializer
init<T>(_ source: T) where T : BinaryFloatingPoint {
//fatalError("\(#function) not implemented")
switch source.floatingPointClass {
case .negativeNormal where source > -1.0:
fallthrough
case .negativeSubnormal, .negativeZero, .positiveZero, .positiveSubnormal:
self.init(_truncatingBits: 0)
case .positiveNormal:
precondition(T.significandBitCount < 72)
var copy: UInt72 = 1
copy <<= T.significandBitCount // inlining 'transparent' functions forms circular loop
copy |= UInt72(exactly: source.significandBitPattern)!
copy >>= T.significandBitCount - (source.significandWidth + 1)
self.init(highOrderBits: copy.high, lowOrderBits: copy.low)
default:
preconditionFailure("Out-of-range value")
}
}
// FixedWidthInteger core math
func addingReportingOverflow(_ rhs: UInt72) -> (partialValue: UInt72, overflow: Bool) {
fatalError("\(#function) not implemented")
}
func dividedReportingOverflow(by rhs: UInt72) -> (partialValue: UInt72, overflow: Bool) {
fatalError("\(#function) not implemented")
}
func dividingFullWidth(_ dividend: (high: UInt72, low: UInt72)) -> (quotient: UInt72, remainder: UInt72) {
fatalError("\(#function) not implemented")
}
func multipliedReportingOverflow(by rhs: UInt72) -> (partialValue: UInt72, overflow: Bool) {
fatalError("\(#function) not implemented")
}
func multipliedFullWidth(by other: UInt72) -> (high: UInt72, low: UInt72) {
fatalError("\(#function) not implemented")
}
func remainderReportingOverflow(dividingBy rhs: UInt72) -> (partialValue: UInt72, overflow: Bool) {
fatalError("\(#function) not implemented")
}
func subtractingReportingOverflow(_ rhs: UInt72) -> (partialValue: UInt72, overflow: Bool) {
fatalError("\(#function) not implemented")
}
// BinaryInteger operators
static func %(lhs: UInt72, rhs: UInt72) -> UInt72 {
let results = lhs.remainderReportingOverflow(dividingBy: rhs)
assert(!results.overflow)
return results.partialValue
}
static func *(lhs: UInt72, rhs: UInt72) -> UInt72 {
let results = lhs.multipliedReportingOverflow(by: rhs)
assert(!results.overflow)
return results.partialValue
}
static func +(lhs: UInt72, rhs: UInt72) -> UInt72 {
let results = lhs.addingReportingOverflow(rhs)
assert(!results.overflow)
return results.partialValue
}
static func -(lhs: UInt72, rhs: UInt72) -> UInt72 {
let results = lhs.subtractingReportingOverflow(rhs)
assert(!results.overflow)
return results.partialValue
}
static func /(lhs: UInt72, rhs: UInt72) -> UInt72 {
let results = lhs.dividedReportingOverflow(by: rhs)
assert(!results.overflow)
return results.partialValue
}
static func %=(lhs: inout UInt72, rhs: UInt72) { lhs = lhs % rhs }
static func *=(lhs: inout UInt72, rhs: UInt72) { lhs = lhs * rhs }
static func +=(lhs: inout UInt72, rhs: UInt72) { lhs = lhs + rhs }
static func -=(lhs: inout UInt72, rhs: UInt72) { lhs = lhs - rhs }
static func /=(lhs: inout UInt72, rhs: UInt72) { lhs = lhs / rhs }
}
Compiling to test on this file flagged an error on the floating-point initializer. There's a comment about transparency and recursive calls. So I added that fatalError
call and commented out the rest of the initializer.
...Now to add a test case that would need to call UInt72
's bit-twiddling code....
...Oh, I don't call anything besides the words
property, and I handle the resulting [UInt]
myself. It seems I'll have to go out of my way to test what happens.
...
OK, I'll add
XCTAssertEqual(String(reflecting: longword), "UInt72(AA,EEEEEEEEEEEEEEEE)")
at the end of my test case. Now I'll shift up by 1:
XCTAssertEqual(String(reflecting: longword << 1), "UInt72(55,DDDDDDDDDDDDDDDC)")
and it builds just fine! When I run it as a test-suite, I get a compiler error: inlining 'transparent' functions forms circular loop
while pointing at the "l" of longword << 1
. So I still don't know whether there's an implementation somewhere that the compiler's choking on, or if it's the flagging the assignment versions as missing, because the compiler doesn't get that far.