66// Copyright © 2016-2017 Károly Lőrentey.
77//
88
9+ #if canImport(Foundation)
910import Foundation
11+ #endif
1012
1113extension BigUInt {
1214 //MARK: NSData Conversion
@@ -43,70 +45,52 @@ extension BigUInt {
4345 assert ( c == 0 && word == 0 && index == - 1 )
4446 }
4547
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.
5151 precondition ( Word . bitWidth % 8 == 0 )
5252
53- self . init ( )
53+ let byteCount = ( self . bitWidth + 7 ) / 8
5454
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
7667 }
68+ i -= 1
7769 }
78- return word
7970 }
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+ } )
8181 }
8282
8383 /// Return a `Data` value that contains the base-256 representation of this integer, in network (big-endian) byte order.
8484 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 ( ) }
8990
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)
10992 }
93+ #endif
11094}
11195
11296extension BigInt {
@@ -133,47 +117,47 @@ extension BigInt {
133117
134118 self . magnitude = BigUInt ( UnsafeRawBufferPointer ( rebasing: buffer. dropFirst ( 1 ) ) )
135119 }
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)
137143 /// Initializes an integer from the bits stored inside a piece of `Data`.
138144 /// The data is assumed to be in network (big-endian) byte order with a first
139145 /// byte to represent the sign (0 for positive, 1 for negative)
140146 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+ } )
159150 }
160151
161152 /// 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)
162153 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)
178161 }
162+ #endif
179163}
0 commit comments