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