spb/os-vault Public
Self-custody, multi-chain crypto wallet for macOS. One recovery phrase, six chain families, zero API keys — nothing leaves your Mac.
Swift 96%
Shell 3.4%
Makefile 0.6%
1import Accelerate.vecLib2import Foundation34public typealias UInt1X = FixedWidthInteger & BinaryInteger & UnsignedInteger & Codable56public struct UInt2X<Word: UInt1X>: Hashable, Codable {7 public typealias IntegerLiteralType = UInt648 public typealias Magnitude = UInt2X9 public typealias Words = [Word.Words.Element]10 public typealias Stride = Int11 // internally it is least significant word first to make Accelerate happy12 public var lo: Word = 013 public var hi: Word = 014 public init(hi: Word, lo: Word) { (self.hi, self.lo) = (hi, lo) }15 public init(_ source: UInt2X) { (hi, lo) = (source.hi, source.lo) }16}1718// Swift bug?19// auto-generated == incorrectly reports20// UInt2X(hi:nonzero, lo:0) == 0 is true21public extension UInt2X {22 static func == (_ lhs: UInt2X, _ rhs: UInt2X) -> Bool {23 lhs.hi == rhs.hi && lhs.lo == rhs.lo24 }25}2627extension UInt2X: ExpressibleByIntegerLiteral {28 public static var isSigned: Bool { false }29 public static var bitWidth: Int {30 Word.bitWidth * 231 }3233 public static var min: UInt2X { UInt2X(hi: Word.min, lo: Word.min) }34 public static var max: UInt2X { UInt2X(hi: Word.max, lo: Word.max) }35 public init(_ source: Word) {36 (hi, lo) = (0, source)37 }3839 public init?<T>(exactly source: T) where T: BinaryInteger {40 guard source.bitWidth <= UInt2X.bitWidth || source <= T(UInt2X.max) else {41 return nil42 }43 self.init(source)44 }4546 public init<T>(_ source: T) where T: BinaryInteger {47 hi = Word(source.magnitude >> Word.bitWidth)48 lo = Word(truncatingIfNeeded: source.magnitude)49 }5051 public init?<T>(exactly source: T) where T: BinaryFloatingPoint {52 print("\(#line)", source)53 guard source.sign != .minus else { return nil }54 guard source.exponent < UInt2X.bitWidth else { return nil }55 self = UInt2X(source.significandBitPattern | (1 << T.significandBitCount))56 self <<= Int(source.exponent) - T.significandBitCount57 }5859 public init<T>(_ source: T) where T: BinaryFloatingPoint {60 guard let result = UInt2X(exactly: source) else {61 fatalError("Not enough bits to represent a signed value")62 }63 self = result64 }6566 // alway succeeds67 public init<T: BinaryInteger>(truncatingIfNeeded source: T) {68 hi = Word(truncatingIfNeeded: source.magnitude >> Word.bitWidth)69 lo = Word(truncatingIfNeeded: source.magnitude)70 }7172 // alway succeeds73 public init<T: BinaryInteger>(clamping source: T) {74 self = UInt2X(exactly: source) ?? UInt2X.max75 }7677 public init(integerLiteral value: IntegerLiteralType) {78 self.init(value)79 }80}8182// Comparable83extension UInt2X: Comparable {84 public static func < (lhs: UInt2X, rhs: UInt2X) -> Bool {85 lhs.hi < rhs.hi ? true : lhs.hi == rhs.hi && lhs.lo < rhs.lo86 }87}8889// Accelerate support90// careful with the significance order. Accerelate is least significant first.91#if os(macOS) || os(iOS)92 import Accelerate93#endif94public enum Int2XConfig {95 #if os(macOS) || os(iOS)96 public static var useAccelerate = true97 #else98 public static let useAccelerate = false99 #endif100}101102// numeric103extension UInt2X: Numeric {104 public var magnitude: UInt2X {105 self106 }107108 // unary operators109 public static prefix func ~ (_ value: UInt2X) -> UInt2X {110 UInt2X(hi: ~value.hi, lo: ~value.lo)111 }112113 public static prefix func + (_ value: UInt2X) -> UInt2X {114 value115 }116117 public static prefix func - (_ value: UInt2X) -> UInt2X {118 ~value &+ 1 // two's complement119 }120121 // additions122 public func addingReportingOverflow(_ other: UInt2X) -> (partialValue: UInt2X, overflow: Bool) {123 guard self != 0 else { return (other, false) }124 guard other != 0 else { return (self, false) }125 #if os(macOS)126 if Int2XConfig.useAccelerate {127 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).addingReportingOverflow(\(other))")128 switch self {129 case is UInt128:130 var a = unsafeBitCast((self, vU128()), to: vU256.self)131 var b = unsafeBitCast((other, vU128()), to: vU256.self)132 var ab = vU256()133 vU256Add(&a, &b, &ab)134 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)135 return (r, o != 0)136 case is UInt256:137 var a = unsafeBitCast((self, vU256()), to: vU512.self)138 var b = unsafeBitCast((other, vU256()), to: vU512.self)139 var ab = vU512()140 vU512Add(&a, &b, &ab)141 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)142 return (r, o != 0)143 case is UInt512:144 var a = unsafeBitCast((self, vU512()), to: vU1024.self)145 var b = unsafeBitCast((other, vU512()), to: vU1024.self)146 var ab = vU1024()147 vU1024Add(&a, &b, &ab)148 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)149 return (r, o != 0)150 default:151 break152 }153 }154 #endif155 var of = false156 let (lv, lf) = lo.addingReportingOverflow(other.lo)157 var (hv, uo) = hi.addingReportingOverflow(other.hi)158 if lf {159 (hv, of) = hv.addingReportingOverflow(1)160 }161 return (partialValue: UInt2X(hi: hv, lo: lv), overflow: uo || of)162 }163164 public func addingReportingOverflow(_ other: Word) -> (partialValue: UInt2X, overflow: Bool) {165 return addingReportingOverflow(UInt2X(hi: 0, lo: other))166 }167168 public static func &+ (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {169 lhs.addingReportingOverflow(rhs).partialValue170 }171172 public static func + (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {173 precondition(~lhs >= rhs, "\(lhs) + \(rhs): Addition overflow!")174 return lhs &+ rhs175 }176177 public static func + (_ lhs: UInt2X, _ rhs: Word) -> UInt2X {178 lhs + UInt2X(hi: 0, lo: rhs)179 }180181 public static func + (_ lhs: Word, _ rhs: UInt2X) -> UInt2X {182 UInt2X(hi: 0, lo: lhs) + rhs183 }184185 public static func += (lhs: inout UInt2X, rhs: UInt2X) {186 lhs = lhs + rhs187 }188189 public static func += (lhs: inout UInt2X, rhs: Word) {190 lhs = lhs + rhs191 }192193 // subtraction194 public func subtractingReportingOverflow(_ other: UInt2X) -> (partialValue: UInt2X, overflow: Bool) {195 guard self != other else { return (0, false) }196 guard self != 0 else { return (-other, false) }197 guard other != 0 else { return (+self, false) }198 #if os(macOS)199 if Int2XConfig.useAccelerate {200 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).subtractingReportingOverflow(\(other))")201 switch self {202 case is UInt128:203 var a = unsafeBitCast((self, vU128()), to: vU256.self)204 var b = unsafeBitCast((other, vU128()), to: vU256.self)205 var ab = vU256()206 vU256Sub(&a, &b, &ab)207 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)208 return (r, o != 0)209 case is UInt256:210 var a = unsafeBitCast((self, vU256()), to: vU512.self)211 var b = unsafeBitCast((other, vU256()), to: vU512.self)212 var ab = vU512()213 vU512Sub(&a, &b, &ab)214 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)215 return (r, o != 0)216 case is UInt512:217 var a = unsafeBitCast((self, vU512()), to: vU1024.self)218 var b = unsafeBitCast((other, vU512()), to: vU1024.self)219 var ab = vU1024()220 vU1024Sub(&a, &b, &ab)221 let (r, o) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)222 return (r, o != 0)223 default:224 break225 }226 }227 #endif228 return addingReportingOverflow(-other)229 }230231 public func subtractingReportingOverflow(_ other: Word) -> (partialValue: UInt2X, overflow: Bool) {232 return subtractingReportingOverflow(UInt2X(hi: 0, lo: other))233 }234235 public static func &- (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {236 lhs.subtractingReportingOverflow(rhs).partialValue237 }238239 public static func - (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {240 precondition(lhs >= rhs, "\(lhs) - \(rhs): Subtraction overflow!")241 return lhs &- rhs242 }243244 public static func - (_ lhs: UInt2X, _ rhs: Word) -> UInt2X {245 lhs - UInt2X(hi: 0, lo: rhs)246 }247248 public static func - (_ lhs: Word, _ rhs: UInt2X) -> UInt2X {249 UInt2X(hi: 0, lo: lhs) - rhs250 }251252 public static func -= (lhs: inout UInt2X, rhs: UInt2X) {253 lhs = lhs - rhs254 }255256 public static func -= (lhs: inout UInt2X, rhs: Word) {257 lhs = lhs - rhs258 }259260 // multiplication261 public func multipliedHalfWidth(by other: Word) -> (high: UInt2X, low: Magnitude) {262 guard self != 0 else { return (0, 0) }263 guard other != 0 else { return (0, 0) }264 let l = lo.multipliedFullWidth(by: other)265 let h = hi.multipliedFullWidth(by: other)266 let r0 = Word(l.low)267 let (r1, o1) = Word(h.low).addingReportingOverflow(Word(l.high))268 let r2 = Word(h.high) &+ (o1 ? 1 : 0) // will not overflow269 return (UInt2X(hi: 0, lo: r2), UInt2X(hi: r1, lo: r0))270 }271272 public func multipliedFullWidth(by other: UInt2X) -> (high: UInt2X, low: Magnitude) {273 guard self != 0 else { return (0, 0) }274 guard other != 0 else { return (0, 0) }275 #if os(macOS)276 if Int2XConfig.useAccelerate {277 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).multipliedFullWidth(by:\(other))")278 switch self {279 case is UInt128:280 var a = unsafeBitCast(self, to: vU128.self)281 var b = unsafeBitCast(other, to: vU128.self)282 var ab = vU256()283 vU128FullMultiply(&a, &b, &ab)284 let (l, h) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)285 return (h, l)286 case is UInt256:287 var a = unsafeBitCast(self, to: vU256.self)288 var b = unsafeBitCast(other, to: vU256.self)289 var ab = vU512()290 vU256FullMultiply(&a, &b, &ab)291 let (l, h) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)292 return (h, l)293 case is UInt512:294 var a = unsafeBitCast(self, to: vU512.self)295 var b = unsafeBitCast(other, to: vU512.self)296 var ab = vU1024()297 vU512FullMultiply(&a, &b, &ab)298 let (l, h) = unsafeBitCast(ab, to: (UInt2X, UInt2X).self)299 return (h, l)300 default:301 break302 }303 }304 #endif305 let l = multipliedHalfWidth(by: other.lo)306 let hs = multipliedHalfWidth(by: other.hi)307 let h = (high: UInt2X(hi: hs.high.lo, lo: hs.low.hi), low: UInt2X(hi: hs.low.lo, lo: 0))308 let (rl, ol) = h.low.addingReportingOverflow(l.low)309 let rh = h.high &+ l.high &+ (ol ? 1 : 0) // will not overflow310 return (rh, rl)311 }312313 public func multipliedReportingOverflow(by other: UInt2X) -> (partialValue: UInt2X, overflow: Bool) {314 guard self != 0 else { return (0, false) }315 guard other != 0 else { return (0, false) }316 let result = multipliedFullWidth(by: other)317 return (result.low, result.high > 0)318 }319320 public static func &* (lhs: UInt2X, rhs: UInt2X) -> UInt2X {321 lhs.multipliedReportingOverflow(by: rhs).partialValue322 }323324 public static func &* (lhs: UInt2X, rhs: Word) -> UInt2X {325 lhs.multipliedHalfWidth(by: rhs).low326 }327328 public static func &* (lhs: Word, rhs: UInt2X) -> UInt2X {329 rhs.multipliedHalfWidth(by: lhs).low330 }331332 public static func * (lhs: UInt2X, rhs: UInt2X) -> UInt2X {333 let result = lhs.multipliedReportingOverflow(by: rhs)334 precondition(!result.overflow, "Multiplication overflow!")335 return result.partialValue336 }337338 public static func * (lhs: UInt2X, rhs: Word) -> UInt2X {339 let result = lhs.multipliedHalfWidth(by: rhs)340 precondition(result.high == 0, "Multiplication overflow!")341 return result.low342 }343344 public static func * (lhs: Word, rhs: UInt2X) -> UInt2X {345 let result = rhs.multipliedHalfWidth(by: lhs)346 precondition(result.high == 0, "Multiplication overflow!")347 return result.low348 }349350 public static func *= (lhs: inout UInt2X, rhs: UInt2X) {351 lhs = lhs * rhs352 }353354 public static func *= (lhs: inout UInt2X, rhs: Word) {355 lhs = lhs * rhs356 }357}358359// bitshifts360public extension UInt2X {361 func rShifted(_ width: Int) -> UInt2X {362 if width < 0 { return lShifted(-width) }363 if width == 0 { return self }364 if width == Word.bitWidth { return UInt2X(hi: 0, lo: hi) }365 #if os(macOS)366 if Int2XConfig.useAccelerate {367 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).rShifted(\(other))")368 switch self {369 case is UInt128:370 var a = unsafeBitCast((self, vU128()), to: vU256.self)371 var r = vU256()372 vLR256Shift(&a, UInt32(width), &r)373 return unsafeBitCast(r, to: (UInt2X, UInt2X).self).0374 case is UInt256:375 var a = unsafeBitCast(self, to: vU256.self)376 var r = vU256()377 vLR256Shift(&a, UInt32(width), &r)378 return unsafeBitCast(r, to: UInt2X.self)379 case is UInt512:380 var a = unsafeBitCast(self, to: vU512.self)381 var r = vU512()382 vLR512Shift(&a, UInt32(width), &r)383 return unsafeBitCast(r, to: UInt2X.self)384 case is UInt1024:385 var a = unsafeBitCast(self, to: vU1024.self)386 var r = vU1024()387 vLR1024Shift(&a, UInt32(width), &r)388 return unsafeBitCast(r, to: UInt2X.self)389 default:390 break391 }392 }393 #endif394 if Word.bitWidth < width {395 return UInt2X(hi: 0, lo: hi >> (width - Word.bitWidth))396 } else {397 let mask = Word((1 << width) &- 1)398 let carry = (hi & mask) << (Word.bitWidth - width)399 return UInt2X(hi: hi >> width, lo: carry | lo >> width)400 }401 }402403 func lShifted(_ width: Int) -> UInt2X {404 if width < 0 { return rShifted(-width) }405 if width == 0 { return self }406 if width == Word.bitWidth { return UInt2X(hi: lo, lo: 0) }407 #if os(macOS)408 if Int2XConfig.useAccelerate {409 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).lShifted(\(other))")410 switch self {411 case is UInt128:412 var a = unsafeBitCast((self, vU128()), to: vU256.self)413 var r = vU256()414 vLL256Shift(&a, UInt32(width), &r)415 return unsafeBitCast(r, to: (UInt2X, UInt2X).self).0416 case is UInt256:417 var a = unsafeBitCast(self, to: vU256.self)418 var r = vU256()419 vLL256Shift(&a, UInt32(width), &r)420 return unsafeBitCast(r, to: UInt2X.self)421 case is UInt512:422 var a = unsafeBitCast(self, to: vU512.self)423 var r = vU512()424 vLL512Shift(&a, UInt32(width), &r)425 return unsafeBitCast(r, to: UInt2X.self)426 case is UInt1024:427 var a = unsafeBitCast(self, to: vU1024.self)428 var r = vU1024()429 vLL1024Shift(&a, UInt32(width), &r)430 return unsafeBitCast(r, to: UInt2X.self)431 default:432 break433 }434 }435 #endif436 if Word.bitWidth < width {437 return UInt2X(hi: lo << (width - Word.bitWidth), lo: 0)438 } else {439 let carry = lo >> (Word.bitWidth - width)440 return UInt2X(hi: hi << width | carry, lo: lo << width)441 }442 }443444 static func &>> (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {445 lhs.rShifted(Int(rhs.lo))446 }447448 static func &>>= (_ lhs: inout UInt2X, _ rhs: UInt2X) {449 return lhs = lhs &>> rhs450 }451452 static func &<< (_ lhs: UInt2X, _ rhs: UInt2X) -> UInt2X {453 lhs.lShifted(Int(rhs.lo))454 }455456 static func &<<= (_ lhs: inout UInt2X, _ rhs: UInt2X) {457 return lhs = lhs &<< rhs458 }459}460461// division, which is rather tough462public extension UInt2X {463 func quotientAndRemainder(dividingBy other: Word) -> (quotient: UInt2X, remainder: UInt2X) {464 precondition(other != 0, "division by zero!")465 let (qh, rh) = hi.quotientAndRemainder(dividingBy: other)466 let (ql, rl) = other.dividingFullWidth((high: rh, low: lo.magnitude))467 return (UInt2X(hi: qh, lo: ql), UInt2X(rl))468 }469470 func quotientAndRemainder(dividingBy other: UInt2X) -> (quotient: UInt2X, remainder: UInt2X) {471 precondition(other != 0, "division by zero!")472 guard other != self else { return (1, 0) }473 guard other < self else { return (0, self) }474 guard other.hi != 0 else {475 return quotientAndRemainder(dividingBy: other.lo)476 }477 #if os(macOS)478 if Int2XConfig.useAccelerate {479 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).quotientAndRemainder(dividingBy:\(other))")480 switch self {481 case is UInt128:482 var a = unsafeBitCast((self, vU128()), to: vU256.self)483 var b = unsafeBitCast((other, vU128()), to: vU256.self)484 var (q, r) = (vU256(), vU256())485 vU256Divide(&a, &b, &q, &r)486 let qq = unsafeBitCast(q, to: (UInt2X, UInt2X).self).0487 let rr = unsafeBitCast(r, to: (UInt2X, UInt2X).self).0488 return (qq, rr)489 case is UInt256:490 var a = unsafeBitCast(self, to: vU256.self)491 var b = unsafeBitCast(other, to: vU256.self)492 var (q, r) = (vU256(), vU256())493 vU256Divide(&a, &b, &q, &r)494 let qq = unsafeBitCast(q, to: UInt2X.self)495 let rr = unsafeBitCast(r, to: UInt2X.self)496 return (qq, rr)497 case is UInt512:498 var a = unsafeBitCast(self, to: vU512.self)499 var b = unsafeBitCast(other, to: vU512.self)500 var (q, r) = (vU512(), vU512())501 vU512Divide(&a, &b, &q, &r)502 let qq = unsafeBitCast(q, to: UInt2X.self)503 let rr = unsafeBitCast(r, to: UInt2X.self)504 return (qq, rr)505 case is UInt1024:506 var a = unsafeBitCast(self, to: vU1024.self)507 var b = unsafeBitCast(other, to: vU1024.self)508 var (q, r) = (vU1024(), vU1024())509 vU1024Divide(&a, &b, &q, &r)510 let qq = unsafeBitCast(q, to: UInt2X.self)511 let rr = unsafeBitCast(r, to: UInt2X.self)512 return (qq, rr)513 default:514 break515 }516 }517 #endif518 #if false519 if Word.bitWidth * 2 <= UInt64.bitWidth { // cheat when we can :-)520 let divided = (UInt64(hi) << Word.bitWidth) + UInt64(lo)521 let divider = (UInt64(other.hi) << Word.bitWidth) + UInt64(other.lo)522 let (q, r) = divided.quotientAndRemainder(dividingBy: divider)523 return (UInt2X(q), UInt2X(r))524 }525 #endif526 // slow but steady bitwise long division527 // print("line \(#line): \(UInt2X.self)(\(self)).quotientAndRemainder(dividingBy:\(other))")528 var (q, r) = (UInt2X(0), UInt2X(0))529 for i in (0 ..< UInt2X.bitWidth).reversed() {530 r <<= 1531 r |= (self >> i) & 1532 if other <= r {533 r -= other534 q |= (1 << i)535 }536 }537 return (q, r)538 }539540 static func / (_ lhs: UInt2X, rhs: UInt2X) -> UInt2X {541 lhs.quotientAndRemainder(dividingBy: rhs).quotient542 }543544 static func /= (_ lhs: inout UInt2X, rhs: UInt2X) {545 lhs = lhs / rhs546 }547548 static func % (_ lhs: UInt2X, rhs: UInt2X) -> UInt2X {549 lhs.quotientAndRemainder(dividingBy: rhs).remainder550 }551552 static func %= (_ lhs: inout UInt2X, rhs: UInt2X) {553 lhs = lhs % rhs554 }555556 func dividedReportingOverflow(by other: UInt2X) -> (partialValue: UInt2X, overflow: Bool) {557 return (self / other, false)558 }559560 func remainderReportingOverflow(dividingBy other: UInt2X) -> (partialValue: UInt2X, overflow: Bool) {561 return (self % other, false)562 }563564 func dividingFullWidth(_ dividend: (high: UInt2X, low: Magnitude)) -> (quotient: UInt2X, remainder: UInt2X) {565 precondition(self != 0, "division by zero!")566 guard dividend.high != 0 else { return dividend.low.quotientAndRemainder(dividingBy: self) }567 #if os(macOS)568 if Int2XConfig.useAccelerate {569 // print("line \(#line):Accelerated! \(UInt2X.self)(\(self)).dividingFullWidth(\(dividend))")570 switch self {571 case is UInt128:572 var a = unsafeBitCast((dividend.low, dividend.high), to: vU256.self)573 var b = unsafeBitCast((self, vU128()), to: vU256.self)574 var (q, r) = (vU256(), vU256())575 vU256Divide(&a, &b, &q, &r)576 let qq = unsafeBitCast(q, to: (UInt2X, UInt2X).self).0577 let rr = unsafeBitCast(r, to: (UInt2X, UInt2X).self).0578 return (qq, rr)579 case is UInt256:580 var a = unsafeBitCast((dividend.low, dividend.high), to: vU512.self)581 var b = unsafeBitCast((self, vU256()), to: vU512.self)582 var (q, r) = (vU512(), vU512())583 vU512Divide(&a, &b, &q, &r)584 let qq = unsafeBitCast(q, to: (UInt2X, UInt2X).self).0585 let rr = unsafeBitCast(r, to: (UInt2X, UInt2X).self).0586 return (qq, rr)587 case is UInt512:588 var a = unsafeBitCast((dividend.low, dividend.high), to: vU1024.self)589 var b = unsafeBitCast((self, vU512()), to: vU1024.self)590 var (q, r) = (vU1024(), vU1024())591 vU1024Divide(&a, &b, &q, &r)592 let qq = unsafeBitCast(q, to: (UInt2X, UInt2X).self).0593 let rr = unsafeBitCast(r, to: (UInt2X, UInt2X).self).0594 return (qq, rr)595 default:596 break597 }598 }599 #endif600 // slow but steady bitwise long division601 // print("line \(#line): \(UInt2X.self)(\(self)).dividingFullWidth(\(dividend))")602 var (q, r) = (UInt2X(0), dividend.high % self)603 for i in (0 ..< UInt2X.bitWidth).reversed() {604 r <<= 1605 r |= (dividend.low >> i) & 1606 if self <= r {607 r -= self608 q |= (1 << i)609 }610 }611 return (q, r)612 }613}614615// UInt2X -> String616extension UInt2X: CustomStringConvertible, CustomDebugStringConvertible {617 public func toString(radix: Int = 10, uppercase: Bool = false) -> String {618 precondition((2 ... 36) ~= radix, "radix must be within the range of 2-36.")619 if self == 0 { return "0" }620 if hi == 0 { return String(lo, radix: radix, uppercase: uppercase) }621 if radix == 16 || radix == 4 || radix == 2 { // time-saver622 let sl = String(lo, radix: radix, uppercase: uppercase)623 let dCount = Word.bitWidth / (radix == 16 ? 4 : radix == 4 ? 2 : 1)624 let zeros = [Character](repeating: "0", count: dCount - sl.count)625 return String(hi, radix: radix, uppercase: uppercase) + String(zeros) + sl626 }627 let digits = uppercase628 ? Array("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")629 : Array("0123456789abcdefghijklmnopqrstuvwxyz")630 #if false // slow but steady digit by digit conversion631 var result = [Character]()632 var qr = (quotient: self, remainder: UInt2X(0))633 repeat {634 qr = qr.quotient.quotientAndRemainder(dividingBy: Word(radix))635 result.append(digits[Int(qr.remainder.lo)])636 } while qr.quotient != UInt2X(0)637 return String(result.reversed())638 #else // faster n-digit-at-once conversion639 let base: UInt64 = [640 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, 0x0000_0000_0000_0000, 0xA8B8_B452_291F_E800, // 0 ~ 3641 0x0000_0000_0000_0000, 0x6765_C793_FA10_0800, 0x41C2_1CB8_E100_0000, 0x3642_7987_5022_6200, // 4 ~ 7642 0x8000_0000_0000_0000, 0xA8B8_B452_291F_E800, 0x8AC7_2304_89E8_0000, 0x4D28_CB56_C33F_A400, // 8 ~ 11643 0x1ECA_170C_0000_0000, 0x780C_7372_621B_D800, 0x1E39_A505_7D81_0000, 0x5B27_AC99_3DF9_7800, // 11 ~ 15644 0x0000_0000_0000_0000, 0x27B9_5E99_7E21_DA00, 0x5DA0_E1E5_3C5C_8000, 0xD2AE_3299_C1C4_B000, // 16 ~ 19645 0x16BC_C41E_9000_0000, 0x2D04_B7FD_D9C0_F000, 0x5658_597B_CAA2_4000, 0xA0E2_0737_3760_9000, // 20 ~ 23646 0x0C29_E980_0000_0000, 0x14AD_F4B7_3203_3500, 0x226E_D364_78BF_A000, 0x383D_9170_B85F_F800, // 24 ~ 27647 0x5A3C_23E3_9C00_0000, 0x8E65_1373_8812_2800, 0xDD41_BB36_D259_E000, 0x0AEE_5720_EE83_0680, // 28 ~ 31648 0x1000_0000_0000_0000, 0x1725_88AD_4F5F_0A00, 0x211E_44F7_D02C_1000, 0x2EE5_6725_F06E_5C00, // 32 ~ 35649 0x41C2_1CB8_E100_0000, // 36650 ][radix]651 let nlen = base.description.count - 1652 // print("base=",base)653 var qr = (quotient: self, remainder: UInt2X(0))654 var result = [UInt64]()655 repeat {656 qr = qr.quotient.quotientAndRemainder(dividingBy: UInt2X(base))657 result.append(UInt64(qr.remainder))658 } while qr.quotient != UInt2X(0)659 let firstDigit = result.removeLast()660 return String(firstDigit, radix: radix, uppercase: uppercase) + result.map {661 let s = String($0, radix: radix, uppercase: uppercase)662 return String([Character](repeating: "0", count: nlen - s.count)) + s663 }.reversed().joined()664 #endif665 }666667 public var description: String {668 toString()669 }670671 public var debugDescription: String {672 "0x" + toString(radix: 16)673 }674}675676public extension StringProtocol {677 init?<Word>(_ source: UInt2X<Word>, radix: Int = 10, uppercase: Bool = false) {678 self.init(source.toString(radix: radix, uppercase: uppercase))679 }680}681682// String <- UInt2X683extension UInt2X: ExpressibleByStringLiteral {684 public init(stringLiteral value: StringLiteralType) {685 self.init()686 if let result = UInt2X.fromString(value) {687 self = result688 }689 }690691 internal static func fromString(_ value: String) -> UInt2X? {692 let radix = UInt2X.radixFromString(value)693 let source = radix == 10 ? value : String(value.dropFirst(2))694 return UInt2X(source, radix: radix)695 }696697 internal static func radixFromString(_ string: String) -> Int {698 switch string.prefix(2) {699 case "0b": return 2700 case "0o": return 8701 case "0x": return 16702 default: return 10703 }704 }705}706707// Int -> UInt2X708public extension Int {709 init<Word>(_ source: UInt2X<Word>) {710 self.init(bitPattern: UInt(source.hi << Word.bitWidth + source.lo))711 }712}713714// Strideable715extension UInt2X: Strideable {716 public func distance(to other: UInt2X) -> Int {717 Int(other) - Int(self)718 }719720 public func advanced(by n: Int) -> UInt2X {721 self + UInt2X(n)722 }723}724725// BinaryInteger726extension UInt2X: BinaryInteger {727 public var bitWidth: Int {728 Word.bitWidth * 2729 }730731 public var words: Words {732 Array(lo.words) + Array(hi.words)733 }734735 public var trailingZeroBitCount: Int {736 hi == 0 ? lo.trailingZeroBitCount : hi.trailingZeroBitCount + Word.bitWidth737 }738739 public static func &= (lhs: inout UInt2X, rhs: UInt2X) {740 lhs = UInt2X(hi: lhs.hi & rhs.hi, lo: lhs.lo & rhs.lo)741 }742743 public static func |= (lhs: inout UInt2X, rhs: UInt2X) {744 lhs = UInt2X(hi: lhs.hi | rhs.hi, lo: lhs.lo | rhs.lo)745 }746747 public static func ^= (lhs: inout UInt2X<Word>, rhs: UInt2X<Word>) {748 lhs = UInt2X(hi: lhs.hi ^ rhs.hi, lo: lhs.lo ^ rhs.lo)749 }750751 public static func <<= <RHS>(lhs: inout UInt2X<Word>, rhs: RHS) where RHS: BinaryInteger {752 lhs = lhs.lShifted(Int(rhs))753 }754755 public static func >>= <RHS>(lhs: inout UInt2X, rhs: RHS) where RHS: BinaryInteger {756 lhs = lhs.rShifted(Int(rhs))757 }758}759760// FixedWidthInteger761extension UInt2X: FixedWidthInteger {762 public init(_truncatingBits _: UInt) {763 fatalError()764 }765766 public var nonzeroBitCount: Int {767 hi.nonzeroBitCount + lo.nonzeroBitCount768 }769770 public var leadingZeroBitCount: Int {771 hi == 0 ? lo.leadingZeroBitCount + Word.bitWidth : hi.leadingZeroBitCount772 }773774 public var byteSwapped: UInt2X {775 UInt2X(hi: lo.byteSwapped, lo: hi.byteSwapped)776 }777}778779// UnsignedInteger780extension UInt2X: UnsignedInteger {}781782public typealias UInt128 = UInt2X<UInt64>783public typealias UInt256 = UInt2X<UInt128>784public typealias UInt512 = UInt2X<UInt256>785public typealias UInt1024 = UInt2X<UInt512>786