Codable.swift 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. //
  2. // Codable.swift
  3. // CS.BigInt
  4. //
  5. // Created by Károly Lőrentey on 2017-8-11.
  6. // Copyright © 2016-2017 Károly Lőrentey.
  7. //
  8. extension CS {
  9. // Little-endian to big-endian
  10. struct Units<Unit: FixedWidthInteger, Words: RandomAccessCollection>: RandomAccessCollection
  11. where Words.Element: FixedWidthInteger, Words.Index == Int {
  12. typealias Word = Words.Element
  13. let words: Words
  14. init(of type: Unit.Type, _ words: Words) {
  15. precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0)
  16. self.words = words
  17. }
  18. var count: Int { return (words.count * Word.bitWidth + Unit.bitWidth - 1) / Unit.bitWidth }
  19. var startIndex: Int { return 0 }
  20. var endIndex: Int { return count }
  21. subscript(_ index: Int) -> Unit {
  22. let index = count - 1 - index
  23. if Unit.bitWidth == Word.bitWidth {
  24. return Unit(words[index])
  25. }
  26. else if Unit.bitWidth > Word.bitWidth {
  27. let c = Unit.bitWidth / Word.bitWidth
  28. var unit: Unit = 0
  29. var j = 0
  30. for i in (c * index) ..< Swift.min(c * (index + 1), words.endIndex) {
  31. unit |= Unit(words[i]) << j
  32. j += Word.bitWidth
  33. }
  34. return unit
  35. }
  36. // Unit.bitWidth < Word.bitWidth
  37. let c = Word.bitWidth / Unit.bitWidth
  38. let i = index / c
  39. let j = index % c
  40. return Unit(truncatingIfNeeded: words[i] >> (j * Unit.bitWidth))
  41. }
  42. }
  43. }
  44. extension Array where Element: FixedWidthInteger {
  45. // Big-endian to little-endian
  46. init<Unit: FixedWidthInteger>(count: Int?, generator: () throws -> Unit?) rethrows {
  47. typealias Word = Element
  48. precondition(Word.bitWidth % Unit.bitWidth == 0 || Unit.bitWidth % Word.bitWidth == 0)
  49. self = []
  50. if Unit.bitWidth == Word.bitWidth {
  51. if let count = count {
  52. self.reserveCapacity(count)
  53. }
  54. while let unit = try generator() {
  55. self.append(Word(unit))
  56. }
  57. }
  58. else if Unit.bitWidth > Word.bitWidth {
  59. let wordsPerUnit = Unit.bitWidth / Word.bitWidth
  60. if let count = count {
  61. self.reserveCapacity(count * wordsPerUnit)
  62. }
  63. while let unit = try generator() {
  64. var shift = Unit.bitWidth - Word.bitWidth
  65. while shift >= 0 {
  66. self.append(Word(truncatingIfNeeded: unit >> shift))
  67. shift -= Word.bitWidth
  68. }
  69. }
  70. }
  71. else {
  72. let unitsPerWord = Word.bitWidth / Unit.bitWidth
  73. if let count = count {
  74. self.reserveCapacity((count + unitsPerWord - 1) / unitsPerWord)
  75. }
  76. var word: Word = 0
  77. var c = 0
  78. while let unit = try generator() {
  79. word <<= Unit.bitWidth
  80. word |= Word(unit)
  81. c += Unit.bitWidth
  82. if c == Word.bitWidth {
  83. self.append(word)
  84. word = 0
  85. c = 0
  86. }
  87. }
  88. if c > 0 {
  89. self.append(word << c)
  90. var shifted: Word = 0
  91. for i in self.indices {
  92. let word = self[i]
  93. self[i] = shifted | (word >> c)
  94. shifted = word << (Word.bitWidth - c)
  95. }
  96. }
  97. }
  98. self.reverse()
  99. }
  100. }
  101. extension CS.BigInt: Codable {
  102. public init(from decoder: Decoder) throws {
  103. var container = try decoder.unkeyedContainer()
  104. // Decode sign
  105. let sign: CS.BigInt.Sign
  106. switch try container.decode(String.self) {
  107. case "+":
  108. sign = .plus
  109. case "-":
  110. sign = .minus
  111. default:
  112. throw DecodingError.dataCorrupted(.init(codingPath: container.codingPath,
  113. debugDescription: "Invalid big integer sign"))
  114. }
  115. // Decode magnitude
  116. let words = try [UInt](count: container.count?.advanced(by: -1)) { () -> UInt64? in
  117. guard !container.isAtEnd else { return nil }
  118. return try container.decode(UInt64.self)
  119. }
  120. let magnitude = CS.BigUInt(words: words)
  121. self.init(sign: sign, magnitude: magnitude)
  122. }
  123. public func encode(to encoder: Encoder) throws {
  124. var container = encoder.unkeyedContainer()
  125. try container.encode(sign == .plus ? "+" : "-")
  126. let units = CS.Units(of: UInt64.self, self.magnitude.words)
  127. if units.isEmpty {
  128. try container.encode(0 as UInt64)
  129. }
  130. else {
  131. try container.encode(contentsOf: units)
  132. }
  133. }
  134. }
  135. extension CS.BigUInt: Codable {
  136. public init(from decoder: Decoder) throws {
  137. let value = try CS.BigInt(from: decoder)
  138. guard value.sign == .plus else {
  139. throw DecodingError.dataCorrupted(.init(codingPath: decoder.codingPath,
  140. debugDescription: "BigUInt cannot hold a negative value"))
  141. }
  142. self = value.magnitude
  143. }
  144. public func encode(to encoder: Encoder) throws {
  145. try CS.BigInt(sign: .plus, magnitude: self).encode(to: encoder)
  146. }
  147. }