Testing out a 4-bit unsigned integer type:
public struct UInt4: FixedWidthInteger, UnsignedInteger {
public init(integerLiteral value: UInt) {
self.init(exactly: value)! //self.init(value)
}
public static func * (lhs: UInt4, rhs: UInt4) -> UInt4 {
let result = lhs.multipliedReportingOverflow(by: rhs)
precondition(!result.overflow)
return result.partialValue
}
public static func *= (lhs: inout UInt4, rhs: UInt4) { lhs = lhs * rhs }
public static func + (lhs: UInt4, rhs: UInt4) -> UInt4 {
let result = lhs.addingReportingOverflow(rhs)
precondition(!result.overflow)
return result.partialValue
}
public static func += (lhs: inout UInt4, rhs: UInt4) { lhs = lhs + rhs }
public static func - (lhs: UInt4, rhs: UInt4) -> UInt4 {
let result = lhs.subtractingReportingOverflow(rhs)
precondition(!result.overflow)
return result.partialValue
}
public static func -= (lhs: inout UInt4, rhs: UInt4) { lhs = lhs - rhs }
public var hashValue: Int { return value.hashValue }
public init<T: BinaryFloatingPoint>(_ source: T) {
fatalError("\(#function) not implemented.")
}
public var words: UInt8.Words { return value.words }
public var trailingZeroBitCount: Int { return Swift.max(value.trailingZeroBitCount, bitWidth) }
public func quotientAndRemainder(dividingBy rhs: UInt4) -> (quotient: UInt4, remainder: UInt4) {
return rhs.dividingFullWidth((high: 0, low: self))
}
public func signum() -> UInt4 { return UInt4(truncatingIfNeeded: value.signum()) }
public static func &= (lhs: inout UInt4, rhs: UInt4) { lhs.value &= rhs.value }
public static func / (lhs: UInt4, rhs: UInt4) -> UInt4 {
let result = lhs.dividedReportingOverflow(by: rhs)
precondition(!result.overflow)
return result.partialValue
}
public static func /= (lhs: inout UInt4, rhs: UInt4) { lhs = lhs / rhs }
public static func % (lhs: UInt4, rhs: UInt4) -> UInt4 {
let result = lhs.remainderReportingOverflow(dividingBy: rhs)
precondition(!result.overflow)
return result.partialValue
}
public static func %= (lhs: inout UInt4, rhs: UInt4) { lhs = lhs % rhs }
public static func ^= (lhs: inout UInt4, rhs: UInt4) { lhs.value ^= rhs.value }
public static func |= (lhs: inout UInt4, rhs: UInt4) { lhs.value |= rhs.value }
public init(_truncatingBits value: UInt) {
self.value = UInt8(truncatingIfNeeded: value) & 0x0F
}
public var nonzeroBitCount: Int { return value.nonzeroBitCount }
public var leadingZeroBitCount: Int { return value.leadingZeroBitCount - 4 }
public var byteSwapped: UInt4 { return self }
public func addingReportingOverflow(_ rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) {
let result = value.addingReportingOverflow(rhs.value)
assert(!result.overflow)
return (UInt4(truncatingIfNeeded: result.partialValue), result.partialValue >> 4 != 0)
}
public func subtractingReportingOverflow(_ rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) {
let result = value.subtractingReportingOverflow(rhs.value)
return (UInt4(truncatingIfNeeded: result.partialValue), result.overflow)
}
public func multipliedReportingOverflow(by rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) {
let result = value.multipliedReportingOverflow(by: rhs.value)
assert(!result.overflow)
return (UInt4(truncatingIfNeeded: result.partialValue), result.partialValue >> 4 != 0)
}
public func dividedReportingOverflow(by rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) {
let result = value.dividedReportingOverflow(by: rhs.value)
return (UInt4(truncatingIfNeeded: result.partialValue), result.overflow)
}
public func remainderReportingOverflow(dividingBy rhs: UInt4) -> (partialValue: UInt4, overflow: Bool) {
let result = value.remainderReportingOverflow(dividingBy: rhs.value)
return (UInt4(truncatingIfNeeded: result.partialValue), result.overflow)
}
public func multipliedFullWidth(by other: UInt4) -> (high: UInt4, low: UInt4) {
let result = value.multipliedFullWidth(by: other.value)
assert(result.high == 0)
return (UInt4(truncatingIfNeeded: result.low >> 4), UInt4(truncatingIfNeeded: result.low))
}
public func dividingFullWidth(_ dividend: (high: UInt4, low: UInt4)) -> (quotient: UInt4, remainder: UInt4) {
let result = value.dividingFullWidth((high: 0, low: dividend.high.value << 4 | dividend.low.value))
precondition(result.quotient & 0xF0 == 0)
return (UInt4(truncatingIfNeeded: result.quotient), UInt4(truncatingIfNeeded: result.remainder))
}
public static var bitWidth: Int { return 4 }
public static func &<<= (lhs: inout UInt4, rhs: UInt4) { lhs.value <<= (rhs.value & 0x03) ; lhs.value &= 0x0F }
public static func &>>= (lhs: inout UInt4, rhs: UInt4) { lhs.value >>= (rhs.value & 0x03) }
/// The raw value.
var value: UInt8
}
With this code, first in a playground, now in a CLI project so I can set breakpoints:
print(UInt8.bitWidth, UInt4.bitWidth)
print(UInt4(_truncatingBits: 22))
print(UInt4(6))
The first two lines work. (That second line prints "6" as it should.) But the third line hangs. In the playground version, it was showing that "bitWidth
" was being called thousands of times before giving up with bad-access. Now that I can use breakpoints, the third line goes:
- Calls the
ExpressibleByIntegerLiteral
initializer - Which calls whichever to the two
BinaryInteger
initializers I didn't comment out. - Calls some initializer within
UnsignedInteger
(whose code is in assembly). - Which calls my integer-literal initializer again!
So I got infinite recursion.
Help.