6
6
// Copyright © 2016-2017 Károly Lőrentey.
7
7
//
8
8
9
+ #if canImport(Foundation)
9
10
import Foundation
11
+ #endif
10
12
11
13
extension BigUInt {
12
14
//MARK: NSData Conversion
@@ -43,70 +45,52 @@ extension BigUInt {
43
45
assert ( c == 0 && word == 0 && index == - 1 )
44
46
}
45
47
46
-
47
- /// Initializes an integer from the bits stored inside a piece of `Data`.
48
- /// The data is assumed to be in network (big-endian) byte order.
49
- public init ( _ data: Data ) {
50
- // This assumes Word is binary.
48
+ /// Return a `UnsafeRawBufferPointer` buffer that contains the base-256 representation of this integer, in network (big-endian) byte order.
49
+ public func serializeToBuffer( ) -> UnsafeRawBufferPointer {
50
+ // This assumes Digit is binary.
51
51
precondition ( Word . bitWidth % 8 == 0 )
52
52
53
- self . init ( )
53
+ let byteCount = ( self . bitWidth + 7 ) / 8
54
54
55
- let length = data. count
56
- guard length > 0 else { return }
57
- let bytesPerDigit = Word . bitWidth / 8
58
- var index = length / bytesPerDigit
59
- var c = bytesPerDigit - length % bytesPerDigit
60
- if c == bytesPerDigit {
61
- c = 0
62
- index -= 1
63
- }
64
- let word : Word = data. withUnsafeBytes { buffPtr in
65
- var word : Word = 0
66
- let p = buffPtr. bindMemory ( to: UInt8 . self)
67
- for byte in p {
68
- word <<= 8
69
- word += Word ( byte)
70
- c += 1
71
- if c == bytesPerDigit {
72
- self [ index] = word
73
- index -= 1
74
- c = 0
75
- word = 0
55
+ let buffer = UnsafeMutableBufferPointer< UInt8> . allocate( capacity: byteCount)
56
+
57
+ guard byteCount > 0 else { return UnsafeRawBufferPointer ( start: buffer. baseAddress, count: 0 ) }
58
+
59
+ var i = byteCount - 1
60
+ for var word in self . words {
61
+ for _ in 0 ..< Word . bitWidth / 8 {
62
+ buffer [ i] = UInt8 ( word & 0xFF )
63
+ word >>= 8
64
+ if i == 0 {
65
+ assert ( word == 0 )
66
+ break
76
67
}
68
+ i -= 1
77
69
}
78
- return word
79
70
}
80
- assert ( c == 0 && word == 0 && index == - 1 )
71
+ return UnsafeRawBufferPointer ( start: buffer. baseAddress, count: byteCount)
72
+ }
73
+
74
+ #if canImport(Foundation)
75
+ /// Initializes an integer from the bits stored inside a piece of `Data`.
76
+ /// The data is assumed to be in network (big-endian) byte order.
77
+ public init ( _ data: Data ) {
78
+ self = data. withUnsafeBytes ( { buffer in
79
+ BigUInt ( buffer)
80
+ } )
81
81
}
82
82
83
83
/// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order.
84
84
public func serialize( ) -> Data {
85
- // This assumes Digit is binary.
86
- precondition ( Word . bitWidth % 8 == 0 )
87
-
88
- let byteCount = ( self . bitWidth + 7 ) / 8
85
+ let buffer = serializeToBuffer ( )
86
+ defer { buffer. deallocate ( ) }
87
+ guard
88
+ let pointer = buffer. baseAddress. map ( UnsafeMutableRawPointer . init ( mutating: ) )
89
+ else { return Data ( ) }
89
90
90
- guard byteCount > 0 else { return Data ( ) }
91
-
92
- var data = Data ( count: byteCount)
93
- data. withUnsafeMutableBytes { buffPtr in
94
- let p = buffPtr. bindMemory ( to: UInt8 . self)
95
- var i = byteCount - 1
96
- for var word in self . words {
97
- for _ in 0 ..< Word . bitWidth / 8 {
98
- p [ i] = UInt8 ( word & 0xFF )
99
- word >>= 8
100
- if i == 0 {
101
- assert ( word == 0 )
102
- break
103
- }
104
- i -= 1
105
- }
106
- }
107
- }
108
- return data
91
+ return Data ( bytes: pointer, count: buffer. count)
109
92
}
93
+ #endif
110
94
}
111
95
112
96
extension BigInt {
@@ -133,47 +117,47 @@ extension BigInt {
133
117
134
118
self . magnitude = BigUInt ( UnsafeRawBufferPointer ( rebasing: buffer. dropFirst ( 1 ) ) )
135
119
}
136
-
120
+
121
+ /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative)
122
+ public func serializeToBuffer( ) -> UnsafeRawBufferPointer {
123
+ // Create a data object for the magnitude portion of the BigInt
124
+ let magnitudeBuffer = self . magnitude. serializeToBuffer ( )
125
+
126
+ // Similar to BigUInt, a value of 0 should return an empty buffer
127
+ guard magnitudeBuffer. count > 0 else { return magnitudeBuffer }
128
+
129
+ // Create a new buffer for the signed BigInt value
130
+ let newBuffer = UnsafeMutableRawBufferPointer . allocate ( byteCount: magnitudeBuffer. count + 1 , alignment: 8 )
131
+ let magnitudeSection = UnsafeMutableRawBufferPointer ( rebasing: newBuffer [ 1 ... ] )
132
+ magnitudeSection. copyBytes ( from: magnitudeBuffer)
133
+ magnitudeBuffer. deallocate ( )
134
+
135
+ // The first byte should be 0 for a positive value, or 1 for a negative value
136
+ // i.e., the sign bit is the LSB
137
+ newBuffer [ 0 ] = self . sign == . plus ? 0 : 1
138
+
139
+ return UnsafeRawBufferPointer ( start: newBuffer. baseAddress, count: newBuffer. count)
140
+ }
141
+
142
+ #if canImport(Foundation)
137
143
/// Initializes an integer from the bits stored inside a piece of `Data`.
138
144
/// The data is assumed to be in network (big-endian) byte order with a first
139
145
/// byte to represent the sign (0 for positive, 1 for negative)
140
146
public init ( _ data: Data ) {
141
- // This assumes Word is binary.
142
- // This is the same assumption made when initializing BigUInt from Data
143
- precondition ( Word . bitWidth % 8 == 0 )
144
-
145
- self . init ( )
146
-
147
- // Serialized data for a BigInt should contain at least 2 bytes: one representing
148
- // the sign, and another for the non-zero magnitude. Zero is represented by an
149
- // empty Data struct, and negative zero is not supported.
150
- guard data. count > 1 , let firstByte = data. first else { return }
151
-
152
- // The first byte gives the sign
153
- // This byte is compared to a bitmask to allow additional functionality to be added
154
- // to this byte in the future.
155
- self . sign = firstByte & 0b1 == 0 ? . plus : . minus
156
-
157
- // The remaining bytes are read and stored as the magnitude
158
- self . magnitude = BigUInt ( data. dropFirst ( 1 ) )
147
+ self = data. withUnsafeBytes ( { buffer in
148
+ BigInt ( buffer)
149
+ } )
159
150
}
160
151
161
152
/// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order and a prepended byte to indicate the sign (0 for positive, 1 for negative)
162
153
public func serialize( ) -> Data {
163
- // Create a data object for the magnitude portion of the BigInt
164
- let magnitudeData = self . magnitude. serialize ( )
165
-
166
- // Similar to BigUInt, a value of 0 should return an initialized, empty Data struct
167
- guard magnitudeData. count > 0 else { return magnitudeData }
168
-
169
- // Create a new Data struct for the signed BigInt value
170
- var data = Data ( capacity: magnitudeData. count + 1 )
171
-
172
- // The first byte should be 0 for a positive value, or 1 for a negative value
173
- // i.e., the sign bit is the LSB
174
- data. append ( self . sign == . plus ? 0 : 1 )
175
-
176
- data. append ( magnitudeData)
177
- return data
154
+ let buffer = serializeToBuffer ( )
155
+ defer { buffer. deallocate ( ) }
156
+ guard
157
+ let pointer = buffer. baseAddress. map ( UnsafeMutableRawPointer . init ( mutating: ) )
158
+ else { return Data ( ) }
159
+
160
+ return Data ( bytes: pointer, count: buffer. count)
178
161
}
162
+ #endif
179
163
}
0 commit comments