-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathlong.js
327 lines (295 loc) · 8.81 KB
/
long.js
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
const TWO_PWR_16_DBL = 1 << 16
const TWO_PWR_32_DBL = TWO_PWR_16_DBL * TWO_PWR_16_DBL
const TWO_PWR_24_DBL = 1 << 24
const TWO_PWR_24 = fromInt(TWO_PWR_24_DBL)
const TWO_PWR_64_DBL = TWO_PWR_32_DBL * TWO_PWR_32_DBL
const TWO_PWR_63_DBL = TWO_PWR_64_DBL / 2
const MIN_VALUE = { low: 0 | 0, high: 0x80000000 | 0 }
const MAX_VALUE = { low: 0xFFFFFFFF | 0, high: 0x7FFFFFFF | 0 }
const MAX_UNSIGNED_VALUE = { low: 0xFFFFFFFF | 0, high: 0xFFFFFFFF | 0 }
const ONE = fromInt(1)
const ZERO = fromInt(0)
const UZERO = fromInt(0, true)
const TMP_COMPARE = fromInt(0)
const TMP_MULTI1 = fromInt(0)
const TMP_MULTI2 = fromInt(0)
const TMP_SUBTRACT = fromInt(0)
const TMP_NEGATE = fromInt(0)
const TMP_CONVERT_BUFFER = new ArrayBuffer(8)
const TMP_CONVERT_FLOAT = new Float64Array(TMP_CONVERT_BUFFER)
const TMP_CONVERT_INT = new Uint32Array(TMP_CONVERT_BUFFER)
function fromInt (value, unsigned) {
if (unsigned) {
value >>>= 0
return { low: value, high: (value | 0) < 0 ? -1 : 0 }
}
value |= 0
return { low: value, high: value < 0 ? -1 : 0 }
}
function toNumber (long, unsigned) {
if (unsigned) {
return ((long.high >>> 0) * TWO_PWR_32_DBL) + (long.low >>> 0)
}
return long.high * TWO_PWR_32_DBL + (long.low >>> 0)
}
function isZero (long) {
return long.low === 0 && long.high === 0
}
function isOdd (long) {
return (long.low & 1) === 1
}
function eq (a, b) {
return a.high === b.high && a.low === b.low
}
function isNegative (long, unsigned) {
return !unsigned && long.high < 0
}
function fromFloat (float, target) {
TMP_CONVERT_FLOAT[0] = float
target.low = TMP_CONVERT_INT[0]
target.high = TMP_CONVERT_INT[1]
return target
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L808-L843
function add (long, other, target) {
// Divide each number into 4 chunks of 16 bits, and then sum the chunks.
const a48 = long.high >>> 16
const a32 = long.high & 0xFFFF
const a16 = long.low >>> 16
const a00 = long.low & 0xFFFF
const b48 = other.high >>> 16
const b32 = other.high & 0xFFFF
const b16 = other.low >>> 16
const b00 = other.low & 0xFFFF
let c00 = a00 + b00
let c16 = c00 >>> 16
c00 &= 0xFFFF
c16 += a16 + b16
let c32 = c16 >>> 16
c16 &= 0xFFFF
c32 += a32 + b32
let c48 = c32 >>> 16
c32 &= 0xFFFF
c48 += a48 + b48
c48 &= 0xFFFF
target.low = (c16 << 16) | c00
target.high = (c48 << 16) | c32
return target
}
function not (long, target) {
target.low = ~long.low
target.high = ~long.high
return target
}
function xor (long, other, target) {
target.low = long.low ^ other.low
target.high = long.high ^ other.high
return target
}
function and (long, other, target) {
target.low = long.low & other.low
target.high = long.high & other.high
return target
}
function negate (long, target, unsigned) {
if (!unsigned && eq(long, MIN_VALUE)) {
return copy(MIN_VALUE, target)
}
return add(not(long, TMP_NEGATE), ONE, target)
}
function subtract (long, subtrahend, target, unsigned) {
return add(long, negate(subtrahend, TMP_SUBTRACT, unsigned), target)
}
function compare (a, b, unsigned) {
if (eq(a, b)) {
return 0
}
const aNeg = isNegative(a, unsigned)
const bNeg = isNegative(b, unsigned)
if (aNeg && !bNeg) {
return -1
}
if (!aNeg && bNeg) {
return 1
}
// At this point the sign bits are the same
if (!unsigned) {
return isNegative(subtract(a, b, TMP_COMPARE, unsigned), unsigned) ? -1 : 1
}
// Both are positive if at least one is unsigned
return (b.high >>> 0) > (a.high >>> 0) || (b.high === a.high && (b.low >>> 0) > (a.low >>> 0)) ? -1 : 1
}
function lt (a, b, unsigned) {
return compare(a, b, unsigned) < 0
}
function multiplyRaw (long, multiplier, target, unsigned) {
// If both longs are small, use float multiplication
if (lt(long, TWO_PWR_24, unsigned) && lt(multiplier, TWO_PWR_24, unsigned)) {
const numa = toNumber(long, unsigned)
const numb = toNumber(multiplier, unsigned)
const multiplied = numa * numb
fromNumber(multiplied, target, unsigned)
return target
}
// Divide each long into 4 chunks of 16 bits, and then add up 4x4 products.
// We can skip products that would overflow.
const a48 = long.high >>> 16
const a32 = long.high & 0xFFFF
const a16 = long.low >>> 16
const a00 = long.low & 0xFFFF
const b48 = multiplier.high >>> 16
const b32 = multiplier.high & 0xFFFF
const b16 = multiplier.low >>> 16
const b00 = multiplier.low & 0xFFFF
let c00 = a00 * b00
let c16 = c00 >>> 16
c00 &= 0xFFFF
c16 += a16 * b00
let c32 = c16 >>> 16
c16 &= 0xFFFF
c16 += a00 * b16
c32 += c16 >>> 16
c16 &= 0xFFFF
c32 += a32 * b00
let c48 = c32 >>> 16
c32 &= 0xFFFF
c32 += a16 * b16
c48 += c32 >>> 16
c32 &= 0xFFFF
c32 += a00 * b32
c48 += c32 >>> 16
c32 &= 0xFFFF
c48 += a48 * b00 + a32 * b16 + a16 * b32 + a00 * b48
c48 &= 0xFFFF
target.low = (c16 << 16) | c00
target.high = (c48 << 16) | c32
return target
}
// Ported from: https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L161-L178
function fromNumber (value, target, unsigned) {
if (isNaN(value)) {
return copy(unsigned ? UZERO : ZERO, target)
}
if (unsigned) {
if (value < 0) {
return copy(UZERO, target)
}
if (value >= TWO_PWR_64_DBL) {
return copy(MAX_UNSIGNED_VALUE, target)
}
} else {
if (value <= -TWO_PWR_63_DBL) {
return copy(MIN_VALUE, target)
}
if (value + 1 >= TWO_PWR_63_DBL) {
return copy(MAX_VALUE, target)
}
if (value < 0) {
return negate(fromNumber(-value, target, unsigned), target, unsigned)
}
}
target.low = (value % TWO_PWR_32_DBL) | 0
target.high = (value / TWO_PWR_32_DBL) | 0
return target
}
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L865-L940
function multiply (long, multiplier, target, unsigned) {
if (isZero(long) || isZero(multiplier)) {
target.low = 0
target.high = 0
return target
}
if (eq(long, MIN_VALUE)) {
return copy(isOdd(multiplier) ? MIN_VALUE : ZERO, target)
}
if (eq(multiplier, MIN_VALUE)) {
return copy(isOdd(long) ? MIN_VALUE : ZERO, target)
}
if (isNegative(long, unsigned)) {
negate(long, TMP_MULTI1, unsigned)
if (isNegative(multiplier, unsigned)) {
negate(multiplier, TMP_MULTI2, unsigned)
multiplyRaw(TMP_MULTI1, TMP_MULTI2, target, unsigned)
} else {
multiplyRaw(TMP_MULTI1, multiplier, TMP_MULTI2, unsigned)
negate(TMP_MULTI2, target, unsigned)
}
return target
}
if (isNegative(multiplier, unsigned)) {
negate(multiplier, TMP_MULTI1, unsigned)
multiplyRaw(long, TMP_MULTI1, TMP_MULTI2, unsigned)
negate(TMP_MULTI2, target, unsigned)
return target
}
return multiplyRaw(long, multiplier, target, unsigned)
}
function copy (source, target) {
target.low = source.low
target.high = source.high
return target
}
module.exports = {
isZero: isZero,
isOdd: isOdd,
eq: eq,
lt: lt,
compare: compare,
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1157-L1172
shiftRight: function (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = (long.low >>> numBits) | (long.high << (32 - numBits))
target.high = long.high >> numBits
} else {
target.low = long.high >> (numBits - 32)
target.high = long.high >= 0 ? 0 : -1
}
return target
},
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1207-L1219
shiftRightUnsigned: function (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = (long.low >>> numBits) | (long.high << (32 - numBits))
target.high = long.high >>> numBits
} else if (numBits === 32) {
target.low = long.high
target.high = 0
} else {
target.low = long.high >>> (numBits - 32)
target.high = 0
}
return target
},
// Ported from https://github.com/dcodeIO/long.js/blob/ce11b4b2bd3ba1240a057d62018563d99db318f9/src/long.js#L1213-L1219
shiftLeft: function (long, numBits, target) {
if ((numBits &= 63) === 0) {
target.low = long.low
target.high = long.high
} else if (numBits < 32) {
target.low = long.low << numBits
target.high = (long.high << numBits) | (long.low >>> (32 - numBits))
} else {
target.low = 0
target.high = long.low << (numBits - 32)
}
return target
},
multiply: multiply,
add: add,
subtract: subtract,
xor: xor,
and: and,
not: not,
copy: copy,
negate: negate,
fromInt: fromInt,
toNumber: toNumber,
fromNumber: fromNumber,
fromFloat: fromFloat
}