14
14
* See the License for the specific language governing permissions and
15
15
* limitations under the License.
16
16
*/
17
+ import { debugAssert } from '../util/assert' ;
17
18
18
19
19
20
/** These constants are taken from the backend. */
@@ -37,13 +38,10 @@ const BYTE_SIZE = 8;
37
38
*/
38
39
const DEFAULT_BUFFER_SIZE = 1024 ;
39
40
40
- /**
41
- * Converts a JavaScript number to a byte array (using little endian
42
- * encoding).
43
- */
41
+ /** Converts a JavaScript number to a byte array (using big endian encoding). */
44
42
function doubleToLongBits ( value : number ) : Uint8Array {
45
43
const dv = new DataView ( new ArrayBuffer ( 8 ) ) ;
46
- dv . setFloat64 ( 0 , value , false ) ;
44
+ dv . setFloat64 ( 0 , value , /* littleEndian= */ false ) ;
47
45
return new Uint8Array ( dv . buffer ) ;
48
46
}
49
47
@@ -53,6 +51,7 @@ function doubleToLongBits(value: number): Uint8Array {
53
51
* Visible for testing.
54
52
*/
55
53
export function numberOfLeadingZerosInByte ( x : number ) : number {
54
+ debugAssert ( x < 256 , 'Provided value is not a byte: ' + x ) ;
56
55
if ( x === 0 ) {
57
56
return 8 ;
58
57
}
@@ -77,8 +76,12 @@ export function numberOfLeadingZerosInByte(x: number): number {
77
76
78
77
/** Counts the number of leading zeros in the given byte array. */
79
78
function numberOfLeadingZeros ( bytes : Uint8Array ) : number {
79
+ debugAssert (
80
+ bytes . length == 8 ,
81
+ 'Can only count leading zeros in 64-bit numbers'
82
+ ) ;
80
83
let leadingZeros = 0 ;
81
- for ( let i = 0 ; i < bytes . length ; ++ i ) {
84
+ for ( let i = 0 ; i < 8 ; ++ i ) {
82
85
const zeros = numberOfLeadingZerosInByte ( bytes [ i ] & 0xff ) ;
83
86
leadingZeros += zeros ;
84
87
if ( zeros !== 8 ) {
@@ -157,6 +160,8 @@ export class OrderedCodeWriter {
157
160
}
158
161
159
162
writeNumberAscending ( val : number ) : void {
163
+ // Values are encoded with a single byte length prefix, followed by the
164
+ // actual value in big-endian format with leading 0 bytes dropped.
160
165
const value = this . toOrderedBits ( val ) ;
161
166
const len = unsignedNumLength ( value ) ;
162
167
this . ensureAvailable ( 1 + len ) ;
@@ -167,6 +172,8 @@ export class OrderedCodeWriter {
167
172
}
168
173
169
174
writeNumberDescending ( val : number ) : void {
175
+ // Values are encoded with a single byte length prefix, followed by the
176
+ // inverted value in big-endian format with leading 0 bytes dropped.
170
177
const value = this . toOrderedBits ( val ) ;
171
178
const len = unsignedNumLength ( value ) ;
172
179
this . ensureAvailable ( 1 + len ) ;
@@ -185,7 +192,11 @@ export class OrderedCodeWriter {
185
192
*/
186
193
private toOrderedBits ( val : number ) : Uint8Array {
187
194
const value = doubleToLongBits ( val ) ;
195
+ // Check if the first bit is set. We use a bit mask since value[0] is
196
+ // encoded as a number from 0 to 255.
188
197
const isNegative = ( value [ 0 ] & 0x80 ) !== 0 ;
198
+
199
+ // Revert the two complement to get natural ordering
189
200
value [ 0 ] ^= isNegative ? 0xff : 0x80 ;
190
201
for ( let i = 1 ; i < value . length ; ++ i ) {
191
202
value [ i ] ^= isNegative ? 0xff : 0x00 ;
0 commit comments