bson 4.0.4 → 4.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/HISTORY.md +56 -1
- package/README.md +7 -9
- package/bower.json +1 -1
- package/bson.d.ts +983 -0
- package/dist/bson.browser.esm.js +7261 -5004
- package/dist/bson.browser.esm.js.map +1 -0
- package/dist/bson.browser.umd.js +7319 -5099
- package/dist/bson.browser.umd.js.map +1 -0
- package/dist/bson.bundle.js +8168 -9216
- package/dist/bson.bundle.js.map +1 -0
- package/dist/bson.esm.js +5643 -5409
- package/dist/bson.esm.js.map +1 -0
- package/etc/prepare.js +19 -0
- package/lib/binary.js +194 -377
- package/lib/binary.js.map +1 -0
- package/lib/bson.js +200 -243
- package/lib/bson.js.map +1 -0
- package/lib/code.js +36 -39
- package/lib/code.js.map +1 -0
- package/lib/constants.js +78 -203
- package/lib/constants.js.map +1 -0
- package/lib/db_ref.js +79 -79
- package/lib/db_ref.js.map +1 -0
- package/lib/decimal128.js +647 -760
- package/lib/decimal128.js.map +1 -0
- package/lib/double.js +61 -58
- package/lib/double.js.map +1 -0
- package/lib/ensure_buffer.js +22 -18
- package/lib/ensure_buffer.js.map +1 -0
- package/lib/extended_json.js +305 -322
- package/lib/extended_json.js.map +1 -0
- package/lib/float_parser.js +98 -104
- package/lib/float_parser.js.map +1 -0
- package/lib/int_32.js +45 -47
- package/lib/int_32.js.map +1 -0
- package/lib/long.js +876 -16
- package/lib/long.js.map +1 -0
- package/lib/map.js +123 -124
- package/lib/map.js.map +1 -0
- package/lib/max_key.js +21 -23
- package/lib/max_key.js.map +1 -0
- package/lib/min_key.js +21 -23
- package/lib/min_key.js.map +1 -0
- package/lib/objectid.js +264 -382
- package/lib/objectid.js.map +1 -0
- package/lib/parser/calculate_size.js +185 -224
- package/lib/parser/calculate_size.js.map +1 -0
- package/lib/parser/deserializer.js +543 -620
- package/lib/parser/deserializer.js.map +1 -0
- package/lib/parser/serializer.js +774 -918
- package/lib/parser/serializer.js.map +1 -0
- package/lib/parser/utils.js +81 -30
- package/lib/parser/utils.js.map +1 -0
- package/lib/regexp.js +54 -70
- package/lib/regexp.js.map +1 -0
- package/lib/symbol.js +40 -56
- package/lib/symbol.js.map +1 -0
- package/lib/timestamp.js +70 -95
- package/lib/timestamp.js.map +1 -0
- package/lib/uuid.js +48 -0
- package/lib/uuid.js.map +1 -0
- package/lib/validate_utf8.js +32 -33
- package/lib/validate_utf8.js.map +1 -0
- package/package.json +53 -31
- package/src/binary.ts +270 -0
- package/src/bson.ts +326 -0
- package/src/code.ts +57 -0
- package/src/constants.ts +104 -0
- package/src/db_ref.ts +115 -0
- package/src/decimal128.ts +801 -0
- package/src/double.ts +85 -0
- package/src/ensure_buffer.ts +26 -0
- package/src/extended_json.ts +395 -0
- package/src/float_parser.ts +152 -0
- package/src/int_32.ts +64 -0
- package/src/long.ts +1000 -0
- package/src/map.ts +139 -0
- package/src/max_key.ts +33 -0
- package/src/min_key.ts +33 -0
- package/src/objectid.ts +377 -0
- package/src/parser/calculate_size.ts +230 -0
- package/src/parser/deserializer.ts +655 -0
- package/src/parser/serializer.ts +1069 -0
- package/src/parser/utils.ts +93 -0
- package/src/regexp.ts +92 -0
- package/src/symbol.ts +57 -0
- package/src/timestamp.ts +103 -0
- package/src/uuid.ts +57 -0
- package/src/validate_utf8.ts +47 -0
- package/lib/fnv1a.js +0 -48
|
@@ -0,0 +1,801 @@
|
|
|
1
|
+
import { Buffer } from 'buffer';
|
|
2
|
+
import { Long } from './long';
|
|
3
|
+
|
|
4
|
+
const PARSE_STRING_REGEXP = /^(\+|-)?(\d+|(\d*\.\d*))?(E|e)?([-+])?(\d+)?$/;
|
|
5
|
+
const PARSE_INF_REGEXP = /^(\+|-)?(Infinity|inf)$/i;
|
|
6
|
+
const PARSE_NAN_REGEXP = /^(\+|-)?NaN$/i;
|
|
7
|
+
|
|
8
|
+
const EXPONENT_MAX = 6111;
|
|
9
|
+
const EXPONENT_MIN = -6176;
|
|
10
|
+
const EXPONENT_BIAS = 6176;
|
|
11
|
+
const MAX_DIGITS = 34;
|
|
12
|
+
|
|
13
|
+
// Nan value bits as 32 bit values (due to lack of longs)
|
|
14
|
+
const NAN_BUFFER = [
|
|
15
|
+
0x7c,
|
|
16
|
+
0x00,
|
|
17
|
+
0x00,
|
|
18
|
+
0x00,
|
|
19
|
+
0x00,
|
|
20
|
+
0x00,
|
|
21
|
+
0x00,
|
|
22
|
+
0x00,
|
|
23
|
+
0x00,
|
|
24
|
+
0x00,
|
|
25
|
+
0x00,
|
|
26
|
+
0x00,
|
|
27
|
+
0x00,
|
|
28
|
+
0x00,
|
|
29
|
+
0x00,
|
|
30
|
+
0x00
|
|
31
|
+
].reverse();
|
|
32
|
+
// Infinity value bits 32 bit values (due to lack of longs)
|
|
33
|
+
const INF_NEGATIVE_BUFFER = [
|
|
34
|
+
0xf8,
|
|
35
|
+
0x00,
|
|
36
|
+
0x00,
|
|
37
|
+
0x00,
|
|
38
|
+
0x00,
|
|
39
|
+
0x00,
|
|
40
|
+
0x00,
|
|
41
|
+
0x00,
|
|
42
|
+
0x00,
|
|
43
|
+
0x00,
|
|
44
|
+
0x00,
|
|
45
|
+
0x00,
|
|
46
|
+
0x00,
|
|
47
|
+
0x00,
|
|
48
|
+
0x00,
|
|
49
|
+
0x00
|
|
50
|
+
].reverse();
|
|
51
|
+
const INF_POSITIVE_BUFFER = [
|
|
52
|
+
0x78,
|
|
53
|
+
0x00,
|
|
54
|
+
0x00,
|
|
55
|
+
0x00,
|
|
56
|
+
0x00,
|
|
57
|
+
0x00,
|
|
58
|
+
0x00,
|
|
59
|
+
0x00,
|
|
60
|
+
0x00,
|
|
61
|
+
0x00,
|
|
62
|
+
0x00,
|
|
63
|
+
0x00,
|
|
64
|
+
0x00,
|
|
65
|
+
0x00,
|
|
66
|
+
0x00,
|
|
67
|
+
0x00
|
|
68
|
+
].reverse();
|
|
69
|
+
|
|
70
|
+
const EXPONENT_REGEX = /^([-+])?(\d+)?$/;
|
|
71
|
+
|
|
72
|
+
// Extract least significant 5 bits
|
|
73
|
+
const COMBINATION_MASK = 0x1f;
|
|
74
|
+
// Extract least significant 14 bits
|
|
75
|
+
const EXPONENT_MASK = 0x3fff;
|
|
76
|
+
// Value of combination field for Inf
|
|
77
|
+
const COMBINATION_INFINITY = 30;
|
|
78
|
+
// Value of combination field for NaN
|
|
79
|
+
const COMBINATION_NAN = 31;
|
|
80
|
+
|
|
81
|
+
// Detect if the value is a digit
|
|
82
|
+
function isDigit(value: string): boolean {
|
|
83
|
+
return !isNaN(parseInt(value, 10));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Divide two uint128 values
|
|
87
|
+
function divideu128(value: { parts: [number, number, number, number] }) {
|
|
88
|
+
const DIVISOR = Long.fromNumber(1000 * 1000 * 1000);
|
|
89
|
+
let _rem = Long.fromNumber(0);
|
|
90
|
+
|
|
91
|
+
if (!value.parts[0] && !value.parts[1] && !value.parts[2] && !value.parts[3]) {
|
|
92
|
+
return { quotient: value, rem: _rem };
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
for (let i = 0; i <= 3; i++) {
|
|
96
|
+
// Adjust remainder to match value of next dividend
|
|
97
|
+
_rem = _rem.shiftLeft(32);
|
|
98
|
+
// Add the divided to _rem
|
|
99
|
+
_rem = _rem.add(new Long(value.parts[i], 0));
|
|
100
|
+
value.parts[i] = _rem.div(DIVISOR).low;
|
|
101
|
+
_rem = _rem.modulo(DIVISOR);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return { quotient: value, rem: _rem };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Multiply two Long values and return the 128 bit value
|
|
108
|
+
function multiply64x2(left: Long, right: Long): { high: Long; low: Long } {
|
|
109
|
+
if (!left && !right) {
|
|
110
|
+
return { high: Long.fromNumber(0), low: Long.fromNumber(0) };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const leftHigh = left.shiftRightUnsigned(32);
|
|
114
|
+
const leftLow = new Long(left.getLowBits(), 0);
|
|
115
|
+
const rightHigh = right.shiftRightUnsigned(32);
|
|
116
|
+
const rightLow = new Long(right.getLowBits(), 0);
|
|
117
|
+
|
|
118
|
+
let productHigh = leftHigh.multiply(rightHigh);
|
|
119
|
+
let productMid = leftHigh.multiply(rightLow);
|
|
120
|
+
const productMid2 = leftLow.multiply(rightHigh);
|
|
121
|
+
let productLow = leftLow.multiply(rightLow);
|
|
122
|
+
|
|
123
|
+
productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
|
|
124
|
+
productMid = new Long(productMid.getLowBits(), 0)
|
|
125
|
+
.add(productMid2)
|
|
126
|
+
.add(productLow.shiftRightUnsigned(32));
|
|
127
|
+
|
|
128
|
+
productHigh = productHigh.add(productMid.shiftRightUnsigned(32));
|
|
129
|
+
productLow = productMid.shiftLeft(32).add(new Long(productLow.getLowBits(), 0));
|
|
130
|
+
|
|
131
|
+
// Return the 128 bit result
|
|
132
|
+
return { high: productHigh, low: productLow };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function lessThan(left: Long, right: Long): boolean {
|
|
136
|
+
// Make values unsigned
|
|
137
|
+
const uhleft = left.high >>> 0;
|
|
138
|
+
const uhright = right.high >>> 0;
|
|
139
|
+
|
|
140
|
+
// Compare high bits first
|
|
141
|
+
if (uhleft < uhright) {
|
|
142
|
+
return true;
|
|
143
|
+
} else if (uhleft === uhright) {
|
|
144
|
+
const ulleft = left.low >>> 0;
|
|
145
|
+
const ulright = right.low >>> 0;
|
|
146
|
+
if (ulleft < ulright) return true;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function invalidErr(string: string, message: string) {
|
|
153
|
+
throw new TypeError(`"${string}" is not a valid Decimal128 string - ${message}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** @public */
|
|
157
|
+
export interface Decimal128Extended {
|
|
158
|
+
$numberDecimal: string;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* A class representation of the BSON Decimal128 type.
|
|
163
|
+
* @public
|
|
164
|
+
*/
|
|
165
|
+
export class Decimal128 {
|
|
166
|
+
_bsontype!: 'Decimal128';
|
|
167
|
+
|
|
168
|
+
readonly bytes: Buffer;
|
|
169
|
+
|
|
170
|
+
/** @param bytes - a buffer containing the raw Decimal128 bytes in little endian order */
|
|
171
|
+
constructor(bytes: Buffer) {
|
|
172
|
+
this.bytes = bytes;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a Decimal128 instance from a string representation
|
|
177
|
+
*
|
|
178
|
+
* @param representation - a numeric string representation.
|
|
179
|
+
*/
|
|
180
|
+
static fromString(representation: string): Decimal128 {
|
|
181
|
+
// Parse state tracking
|
|
182
|
+
let isNegative = false;
|
|
183
|
+
let sawRadix = false;
|
|
184
|
+
let foundNonZero = false;
|
|
185
|
+
|
|
186
|
+
// Total number of significant digits (no leading or trailing zero)
|
|
187
|
+
let significantDigits = 0;
|
|
188
|
+
// Total number of significand digits read
|
|
189
|
+
let nDigitsRead = 0;
|
|
190
|
+
// Total number of digits (no leading zeros)
|
|
191
|
+
let nDigits = 0;
|
|
192
|
+
// The number of the digits after radix
|
|
193
|
+
let radixPosition = 0;
|
|
194
|
+
// The index of the first non-zero in *str*
|
|
195
|
+
let firstNonZero = 0;
|
|
196
|
+
|
|
197
|
+
// Digits Array
|
|
198
|
+
const digits = [0];
|
|
199
|
+
// The number of digits in digits
|
|
200
|
+
let nDigitsStored = 0;
|
|
201
|
+
// Insertion pointer for digits
|
|
202
|
+
let digitsInsert = 0;
|
|
203
|
+
// The index of the first non-zero digit
|
|
204
|
+
let firstDigit = 0;
|
|
205
|
+
// The index of the last digit
|
|
206
|
+
let lastDigit = 0;
|
|
207
|
+
|
|
208
|
+
// Exponent
|
|
209
|
+
let exponent = 0;
|
|
210
|
+
// loop index over array
|
|
211
|
+
let i = 0;
|
|
212
|
+
// The high 17 digits of the significand
|
|
213
|
+
let significandHigh = new Long(0, 0);
|
|
214
|
+
// The low 17 digits of the significand
|
|
215
|
+
let significandLow = new Long(0, 0);
|
|
216
|
+
// The biased exponent
|
|
217
|
+
let biasedExponent = 0;
|
|
218
|
+
|
|
219
|
+
// Read index
|
|
220
|
+
let index = 0;
|
|
221
|
+
|
|
222
|
+
// Naively prevent against REDOS attacks.
|
|
223
|
+
// TODO: implementing a custom parsing for this, or refactoring the regex would yield
|
|
224
|
+
// further gains.
|
|
225
|
+
if (representation.length >= 7000) {
|
|
226
|
+
throw new TypeError('' + representation + ' not a valid Decimal128 string');
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Results
|
|
230
|
+
const stringMatch = representation.match(PARSE_STRING_REGEXP);
|
|
231
|
+
const infMatch = representation.match(PARSE_INF_REGEXP);
|
|
232
|
+
const nanMatch = representation.match(PARSE_NAN_REGEXP);
|
|
233
|
+
|
|
234
|
+
// Validate the string
|
|
235
|
+
if ((!stringMatch && !infMatch && !nanMatch) || representation.length === 0) {
|
|
236
|
+
throw new TypeError('' + representation + ' not a valid Decimal128 string');
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (stringMatch) {
|
|
240
|
+
// full_match = stringMatch[0]
|
|
241
|
+
// sign = stringMatch[1]
|
|
242
|
+
|
|
243
|
+
const unsignedNumber = stringMatch[2];
|
|
244
|
+
// stringMatch[3] is undefined if a whole number (ex "1", 12")
|
|
245
|
+
// but defined if a number w/ decimal in it (ex "1.0, 12.2")
|
|
246
|
+
|
|
247
|
+
const e = stringMatch[4];
|
|
248
|
+
const expSign = stringMatch[5];
|
|
249
|
+
const expNumber = stringMatch[6];
|
|
250
|
+
|
|
251
|
+
// they provided e, but didn't give an exponent number. for ex "1e"
|
|
252
|
+
if (e && expNumber === undefined) invalidErr(representation, 'missing exponent power');
|
|
253
|
+
|
|
254
|
+
// they provided e, but didn't give a number before it. for ex "e1"
|
|
255
|
+
if (e && unsignedNumber === undefined) invalidErr(representation, 'missing exponent base');
|
|
256
|
+
|
|
257
|
+
if (e === undefined && (expSign || expNumber)) {
|
|
258
|
+
invalidErr(representation, 'missing e before exponent');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Get the negative or positive sign
|
|
263
|
+
if (representation[index] === '+' || representation[index] === '-') {
|
|
264
|
+
isNegative = representation[index++] === '-';
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
// Check if user passed Infinity or NaN
|
|
268
|
+
if (!isDigit(representation[index]) && representation[index] !== '.') {
|
|
269
|
+
if (representation[index] === 'i' || representation[index] === 'I') {
|
|
270
|
+
return new Decimal128(Buffer.from(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER));
|
|
271
|
+
} else if (representation[index] === 'N') {
|
|
272
|
+
return new Decimal128(Buffer.from(NAN_BUFFER));
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Read all the digits
|
|
277
|
+
while (isDigit(representation[index]) || representation[index] === '.') {
|
|
278
|
+
if (representation[index] === '.') {
|
|
279
|
+
if (sawRadix) invalidErr(representation, 'contains multiple periods');
|
|
280
|
+
|
|
281
|
+
sawRadix = true;
|
|
282
|
+
index = index + 1;
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (nDigitsStored < 34) {
|
|
287
|
+
if (representation[index] !== '0' || foundNonZero) {
|
|
288
|
+
if (!foundNonZero) {
|
|
289
|
+
firstNonZero = nDigitsRead;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
foundNonZero = true;
|
|
293
|
+
|
|
294
|
+
// Only store 34 digits
|
|
295
|
+
digits[digitsInsert++] = parseInt(representation[index], 10);
|
|
296
|
+
nDigitsStored = nDigitsStored + 1;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (foundNonZero) nDigits = nDigits + 1;
|
|
301
|
+
if (sawRadix) radixPosition = radixPosition + 1;
|
|
302
|
+
|
|
303
|
+
nDigitsRead = nDigitsRead + 1;
|
|
304
|
+
index = index + 1;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (sawRadix && !nDigitsRead)
|
|
308
|
+
throw new TypeError('' + representation + ' not a valid Decimal128 string');
|
|
309
|
+
|
|
310
|
+
// Read exponent if exists
|
|
311
|
+
if (representation[index] === 'e' || representation[index] === 'E') {
|
|
312
|
+
// Read exponent digits
|
|
313
|
+
const match = representation.substr(++index).match(EXPONENT_REGEX);
|
|
314
|
+
|
|
315
|
+
// No digits read
|
|
316
|
+
if (!match || !match[2]) return new Decimal128(Buffer.from(NAN_BUFFER));
|
|
317
|
+
|
|
318
|
+
// Get exponent
|
|
319
|
+
exponent = parseInt(match[0], 10);
|
|
320
|
+
|
|
321
|
+
// Adjust the index
|
|
322
|
+
index = index + match[0].length;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// Return not a number
|
|
326
|
+
if (representation[index]) return new Decimal128(Buffer.from(NAN_BUFFER));
|
|
327
|
+
|
|
328
|
+
// Done reading input
|
|
329
|
+
// Find first non-zero digit in digits
|
|
330
|
+
firstDigit = 0;
|
|
331
|
+
|
|
332
|
+
if (!nDigitsStored) {
|
|
333
|
+
firstDigit = 0;
|
|
334
|
+
lastDigit = 0;
|
|
335
|
+
digits[0] = 0;
|
|
336
|
+
nDigits = 1;
|
|
337
|
+
nDigitsStored = 1;
|
|
338
|
+
significantDigits = 0;
|
|
339
|
+
} else {
|
|
340
|
+
lastDigit = nDigitsStored - 1;
|
|
341
|
+
significantDigits = nDigits;
|
|
342
|
+
if (significantDigits !== 1) {
|
|
343
|
+
while (representation[firstNonZero + significantDigits - 1] === '0') {
|
|
344
|
+
significantDigits = significantDigits - 1;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Normalization of exponent
|
|
350
|
+
// Correct exponent based on radix position, and shift significand as needed
|
|
351
|
+
// to represent user input
|
|
352
|
+
|
|
353
|
+
// Overflow prevention
|
|
354
|
+
if (exponent <= radixPosition && radixPosition - exponent > 1 << 14) {
|
|
355
|
+
exponent = EXPONENT_MIN;
|
|
356
|
+
} else {
|
|
357
|
+
exponent = exponent - radixPosition;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// Attempt to normalize the exponent
|
|
361
|
+
while (exponent > EXPONENT_MAX) {
|
|
362
|
+
// Shift exponent to significand and decrease
|
|
363
|
+
lastDigit = lastDigit + 1;
|
|
364
|
+
|
|
365
|
+
if (lastDigit - firstDigit > MAX_DIGITS) {
|
|
366
|
+
// Check if we have a zero then just hard clamp, otherwise fail
|
|
367
|
+
const digitsString = digits.join('');
|
|
368
|
+
if (digitsString.match(/^0+$/)) {
|
|
369
|
+
exponent = EXPONENT_MAX;
|
|
370
|
+
break;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
invalidErr(representation, 'overflow');
|
|
374
|
+
}
|
|
375
|
+
exponent = exponent - 1;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
while (exponent < EXPONENT_MIN || nDigitsStored < nDigits) {
|
|
379
|
+
// Shift last digit. can only do this if < significant digits than # stored.
|
|
380
|
+
if (lastDigit === 0 && significantDigits < nDigitsStored) {
|
|
381
|
+
exponent = EXPONENT_MIN;
|
|
382
|
+
significantDigits = 0;
|
|
383
|
+
break;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
if (nDigitsStored < nDigits) {
|
|
387
|
+
// adjust to match digits not stored
|
|
388
|
+
nDigits = nDigits - 1;
|
|
389
|
+
} else {
|
|
390
|
+
// adjust to round
|
|
391
|
+
lastDigit = lastDigit - 1;
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (exponent < EXPONENT_MAX) {
|
|
395
|
+
exponent = exponent + 1;
|
|
396
|
+
} else {
|
|
397
|
+
// Check if we have a zero then just hard clamp, otherwise fail
|
|
398
|
+
const digitsString = digits.join('');
|
|
399
|
+
if (digitsString.match(/^0+$/)) {
|
|
400
|
+
exponent = EXPONENT_MAX;
|
|
401
|
+
break;
|
|
402
|
+
}
|
|
403
|
+
invalidErr(representation, 'overflow');
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Round
|
|
408
|
+
// We've normalized the exponent, but might still need to round.
|
|
409
|
+
if (lastDigit - firstDigit + 1 < significantDigits) {
|
|
410
|
+
let endOfString = nDigitsRead;
|
|
411
|
+
|
|
412
|
+
// If we have seen a radix point, 'string' is 1 longer than we have
|
|
413
|
+
// documented with ndigits_read, so inc the position of the first nonzero
|
|
414
|
+
// digit and the position that digits are read to.
|
|
415
|
+
if (sawRadix) {
|
|
416
|
+
firstNonZero = firstNonZero + 1;
|
|
417
|
+
endOfString = endOfString + 1;
|
|
418
|
+
}
|
|
419
|
+
// if negative, we need to increment again to account for - sign at start.
|
|
420
|
+
if (isNegative) {
|
|
421
|
+
firstNonZero = firstNonZero + 1;
|
|
422
|
+
endOfString = endOfString + 1;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
const roundDigit = parseInt(representation[firstNonZero + lastDigit + 1], 10);
|
|
426
|
+
let roundBit = 0;
|
|
427
|
+
|
|
428
|
+
if (roundDigit >= 5) {
|
|
429
|
+
roundBit = 1;
|
|
430
|
+
if (roundDigit === 5) {
|
|
431
|
+
roundBit = digits[lastDigit] % 2 === 1 ? 1 : 0;
|
|
432
|
+
for (i = firstNonZero + lastDigit + 2; i < endOfString; i++) {
|
|
433
|
+
if (parseInt(representation[i], 10)) {
|
|
434
|
+
roundBit = 1;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
if (roundBit) {
|
|
442
|
+
let dIdx = lastDigit;
|
|
443
|
+
|
|
444
|
+
for (; dIdx >= 0; dIdx--) {
|
|
445
|
+
if (++digits[dIdx] > 9) {
|
|
446
|
+
digits[dIdx] = 0;
|
|
447
|
+
|
|
448
|
+
// overflowed most significant digit
|
|
449
|
+
if (dIdx === 0) {
|
|
450
|
+
if (exponent < EXPONENT_MAX) {
|
|
451
|
+
exponent = exponent + 1;
|
|
452
|
+
digits[dIdx] = 1;
|
|
453
|
+
} else {
|
|
454
|
+
return new Decimal128(
|
|
455
|
+
Buffer.from(isNegative ? INF_NEGATIVE_BUFFER : INF_POSITIVE_BUFFER)
|
|
456
|
+
);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
// Encode significand
|
|
465
|
+
// The high 17 digits of the significand
|
|
466
|
+
significandHigh = Long.fromNumber(0);
|
|
467
|
+
// The low 17 digits of the significand
|
|
468
|
+
significandLow = Long.fromNumber(0);
|
|
469
|
+
|
|
470
|
+
// read a zero
|
|
471
|
+
if (significantDigits === 0) {
|
|
472
|
+
significandHigh = Long.fromNumber(0);
|
|
473
|
+
significandLow = Long.fromNumber(0);
|
|
474
|
+
} else if (lastDigit - firstDigit < 17) {
|
|
475
|
+
let dIdx = firstDigit;
|
|
476
|
+
significandLow = Long.fromNumber(digits[dIdx++]);
|
|
477
|
+
significandHigh = new Long(0, 0);
|
|
478
|
+
|
|
479
|
+
for (; dIdx <= lastDigit; dIdx++) {
|
|
480
|
+
significandLow = significandLow.multiply(Long.fromNumber(10));
|
|
481
|
+
significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
|
|
482
|
+
}
|
|
483
|
+
} else {
|
|
484
|
+
let dIdx = firstDigit;
|
|
485
|
+
significandHigh = Long.fromNumber(digits[dIdx++]);
|
|
486
|
+
|
|
487
|
+
for (; dIdx <= lastDigit - 17; dIdx++) {
|
|
488
|
+
significandHigh = significandHigh.multiply(Long.fromNumber(10));
|
|
489
|
+
significandHigh = significandHigh.add(Long.fromNumber(digits[dIdx]));
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
significandLow = Long.fromNumber(digits[dIdx++]);
|
|
493
|
+
|
|
494
|
+
for (; dIdx <= lastDigit; dIdx++) {
|
|
495
|
+
significandLow = significandLow.multiply(Long.fromNumber(10));
|
|
496
|
+
significandLow = significandLow.add(Long.fromNumber(digits[dIdx]));
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
const significand = multiply64x2(significandHigh, Long.fromString('100000000000000000'));
|
|
501
|
+
significand.low = significand.low.add(significandLow);
|
|
502
|
+
|
|
503
|
+
if (lessThan(significand.low, significandLow)) {
|
|
504
|
+
significand.high = significand.high.add(Long.fromNumber(1));
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// Biased exponent
|
|
508
|
+
biasedExponent = exponent + EXPONENT_BIAS;
|
|
509
|
+
const dec = { low: Long.fromNumber(0), high: Long.fromNumber(0) };
|
|
510
|
+
|
|
511
|
+
// Encode combination, exponent, and significand.
|
|
512
|
+
if (
|
|
513
|
+
significand.high.shiftRightUnsigned(49).and(Long.fromNumber(1)).equals(Long.fromNumber(1))
|
|
514
|
+
) {
|
|
515
|
+
// Encode '11' into bits 1 to 3
|
|
516
|
+
dec.high = dec.high.or(Long.fromNumber(0x3).shiftLeft(61));
|
|
517
|
+
dec.high = dec.high.or(
|
|
518
|
+
Long.fromNumber(biasedExponent).and(Long.fromNumber(0x3fff).shiftLeft(47))
|
|
519
|
+
);
|
|
520
|
+
dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x7fffffffffff)));
|
|
521
|
+
} else {
|
|
522
|
+
dec.high = dec.high.or(Long.fromNumber(biasedExponent & 0x3fff).shiftLeft(49));
|
|
523
|
+
dec.high = dec.high.or(significand.high.and(Long.fromNumber(0x1ffffffffffff)));
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
dec.low = significand.low;
|
|
527
|
+
|
|
528
|
+
// Encode sign
|
|
529
|
+
if (isNegative) {
|
|
530
|
+
dec.high = dec.high.or(Long.fromString('9223372036854775808'));
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
// Encode into a buffer
|
|
534
|
+
const buffer = Buffer.alloc(16);
|
|
535
|
+
index = 0;
|
|
536
|
+
|
|
537
|
+
// Encode the low 64 bits of the decimal
|
|
538
|
+
// Encode low bits
|
|
539
|
+
buffer[index++] = dec.low.low & 0xff;
|
|
540
|
+
buffer[index++] = (dec.low.low >> 8) & 0xff;
|
|
541
|
+
buffer[index++] = (dec.low.low >> 16) & 0xff;
|
|
542
|
+
buffer[index++] = (dec.low.low >> 24) & 0xff;
|
|
543
|
+
// Encode high bits
|
|
544
|
+
buffer[index++] = dec.low.high & 0xff;
|
|
545
|
+
buffer[index++] = (dec.low.high >> 8) & 0xff;
|
|
546
|
+
buffer[index++] = (dec.low.high >> 16) & 0xff;
|
|
547
|
+
buffer[index++] = (dec.low.high >> 24) & 0xff;
|
|
548
|
+
|
|
549
|
+
// Encode the high 64 bits of the decimal
|
|
550
|
+
// Encode low bits
|
|
551
|
+
buffer[index++] = dec.high.low & 0xff;
|
|
552
|
+
buffer[index++] = (dec.high.low >> 8) & 0xff;
|
|
553
|
+
buffer[index++] = (dec.high.low >> 16) & 0xff;
|
|
554
|
+
buffer[index++] = (dec.high.low >> 24) & 0xff;
|
|
555
|
+
// Encode high bits
|
|
556
|
+
buffer[index++] = dec.high.high & 0xff;
|
|
557
|
+
buffer[index++] = (dec.high.high >> 8) & 0xff;
|
|
558
|
+
buffer[index++] = (dec.high.high >> 16) & 0xff;
|
|
559
|
+
buffer[index++] = (dec.high.high >> 24) & 0xff;
|
|
560
|
+
|
|
561
|
+
// Return the new Decimal128
|
|
562
|
+
return new Decimal128(buffer);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/** Create a string representation of the raw Decimal128 value */
|
|
566
|
+
toString(): string {
|
|
567
|
+
// Note: bits in this routine are referred to starting at 0,
|
|
568
|
+
// from the sign bit, towards the coefficient.
|
|
569
|
+
|
|
570
|
+
// decoded biased exponent (14 bits)
|
|
571
|
+
let biased_exponent;
|
|
572
|
+
// the number of significand digits
|
|
573
|
+
let significand_digits = 0;
|
|
574
|
+
// the base-10 digits in the significand
|
|
575
|
+
const significand = new Array<number>(36);
|
|
576
|
+
for (let i = 0; i < significand.length; i++) significand[i] = 0;
|
|
577
|
+
// read pointer into significand
|
|
578
|
+
let index = 0;
|
|
579
|
+
|
|
580
|
+
// true if the number is zero
|
|
581
|
+
let is_zero = false;
|
|
582
|
+
|
|
583
|
+
// the most significant significand bits (50-46)
|
|
584
|
+
let significand_msb;
|
|
585
|
+
// temporary storage for significand decoding
|
|
586
|
+
let significand128: { parts: [number, number, number, number] } = { parts: [0, 0, 0, 0] };
|
|
587
|
+
// indexing variables
|
|
588
|
+
let j, k;
|
|
589
|
+
|
|
590
|
+
// Output string
|
|
591
|
+
const string: string[] = [];
|
|
592
|
+
|
|
593
|
+
// Unpack index
|
|
594
|
+
index = 0;
|
|
595
|
+
|
|
596
|
+
// Buffer reference
|
|
597
|
+
const buffer = this.bytes;
|
|
598
|
+
|
|
599
|
+
// Unpack the low 64bits into a long
|
|
600
|
+
// bits 96 - 127
|
|
601
|
+
const low =
|
|
602
|
+
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
603
|
+
// bits 64 - 95
|
|
604
|
+
const midl =
|
|
605
|
+
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
606
|
+
|
|
607
|
+
// Unpack the high 64bits into a long
|
|
608
|
+
// bits 32 - 63
|
|
609
|
+
const midh =
|
|
610
|
+
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
611
|
+
// bits 0 - 31
|
|
612
|
+
const high =
|
|
613
|
+
buffer[index++] | (buffer[index++] << 8) | (buffer[index++] << 16) | (buffer[index++] << 24);
|
|
614
|
+
|
|
615
|
+
// Unpack index
|
|
616
|
+
index = 0;
|
|
617
|
+
|
|
618
|
+
// Create the state of the decimal
|
|
619
|
+
const dec = {
|
|
620
|
+
low: new Long(low, midl),
|
|
621
|
+
high: new Long(midh, high)
|
|
622
|
+
};
|
|
623
|
+
|
|
624
|
+
if (dec.high.lessThan(Long.ZERO)) {
|
|
625
|
+
string.push('-');
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
// Decode combination field and exponent
|
|
629
|
+
// bits 1 - 5
|
|
630
|
+
const combination = (high >> 26) & COMBINATION_MASK;
|
|
631
|
+
|
|
632
|
+
if (combination >> 3 === 3) {
|
|
633
|
+
// Check for 'special' values
|
|
634
|
+
if (combination === COMBINATION_INFINITY) {
|
|
635
|
+
return string.join('') + 'Infinity';
|
|
636
|
+
} else if (combination === COMBINATION_NAN) {
|
|
637
|
+
return 'NaN';
|
|
638
|
+
} else {
|
|
639
|
+
biased_exponent = (high >> 15) & EXPONENT_MASK;
|
|
640
|
+
significand_msb = 0x08 + ((high >> 14) & 0x01);
|
|
641
|
+
}
|
|
642
|
+
} else {
|
|
643
|
+
significand_msb = (high >> 14) & 0x07;
|
|
644
|
+
biased_exponent = (high >> 17) & EXPONENT_MASK;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// unbiased exponent
|
|
648
|
+
const exponent = biased_exponent - EXPONENT_BIAS;
|
|
649
|
+
|
|
650
|
+
// Create string of significand digits
|
|
651
|
+
|
|
652
|
+
// Convert the 114-bit binary number represented by
|
|
653
|
+
// (significand_high, significand_low) to at most 34 decimal
|
|
654
|
+
// digits through modulo and division.
|
|
655
|
+
significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
|
|
656
|
+
significand128.parts[1] = midh;
|
|
657
|
+
significand128.parts[2] = midl;
|
|
658
|
+
significand128.parts[3] = low;
|
|
659
|
+
|
|
660
|
+
if (
|
|
661
|
+
significand128.parts[0] === 0 &&
|
|
662
|
+
significand128.parts[1] === 0 &&
|
|
663
|
+
significand128.parts[2] === 0 &&
|
|
664
|
+
significand128.parts[3] === 0
|
|
665
|
+
) {
|
|
666
|
+
is_zero = true;
|
|
667
|
+
} else {
|
|
668
|
+
for (k = 3; k >= 0; k--) {
|
|
669
|
+
let least_digits = 0;
|
|
670
|
+
// Perform the divide
|
|
671
|
+
const result = divideu128(significand128);
|
|
672
|
+
significand128 = result.quotient;
|
|
673
|
+
least_digits = result.rem.low;
|
|
674
|
+
|
|
675
|
+
// We now have the 9 least significant digits (in base 2).
|
|
676
|
+
// Convert and output to string.
|
|
677
|
+
if (!least_digits) continue;
|
|
678
|
+
|
|
679
|
+
for (j = 8; j >= 0; j--) {
|
|
680
|
+
// significand[k * 9 + j] = Math.round(least_digits % 10);
|
|
681
|
+
significand[k * 9 + j] = least_digits % 10;
|
|
682
|
+
// least_digits = Math.round(least_digits / 10);
|
|
683
|
+
least_digits = Math.floor(least_digits / 10);
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
// Output format options:
|
|
689
|
+
// Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd
|
|
690
|
+
// Regular - ddd.ddd
|
|
691
|
+
|
|
692
|
+
if (is_zero) {
|
|
693
|
+
significand_digits = 1;
|
|
694
|
+
significand[index] = 0;
|
|
695
|
+
} else {
|
|
696
|
+
significand_digits = 36;
|
|
697
|
+
while (!significand[index]) {
|
|
698
|
+
significand_digits = significand_digits - 1;
|
|
699
|
+
index = index + 1;
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
// the exponent if scientific notation is used
|
|
704
|
+
const scientific_exponent = significand_digits - 1 + exponent;
|
|
705
|
+
|
|
706
|
+
// The scientific exponent checks are dictated by the string conversion
|
|
707
|
+
// specification and are somewhat arbitrary cutoffs.
|
|
708
|
+
//
|
|
709
|
+
// We must check exponent > 0, because if this is the case, the number
|
|
710
|
+
// has trailing zeros. However, we *cannot* output these trailing zeros,
|
|
711
|
+
// because doing so would change the precision of the value, and would
|
|
712
|
+
// change stored data if the string converted number is round tripped.
|
|
713
|
+
if (scientific_exponent >= 34 || scientific_exponent <= -7 || exponent > 0) {
|
|
714
|
+
// Scientific format
|
|
715
|
+
|
|
716
|
+
// if there are too many significant digits, we should just be treating numbers
|
|
717
|
+
// as + or - 0 and using the non-scientific exponent (this is for the "invalid
|
|
718
|
+
// representation should be treated as 0/-0" spec cases in decimal128-1.json)
|
|
719
|
+
if (significand_digits > 34) {
|
|
720
|
+
string.push(`${0}`);
|
|
721
|
+
if (exponent > 0) string.push('E+' + exponent);
|
|
722
|
+
else if (exponent < 0) string.push('E' + exponent);
|
|
723
|
+
return string.join('');
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
string.push(`${significand[index++]}`);
|
|
727
|
+
significand_digits = significand_digits - 1;
|
|
728
|
+
|
|
729
|
+
if (significand_digits) {
|
|
730
|
+
string.push('.');
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
for (let i = 0; i < significand_digits; i++) {
|
|
734
|
+
string.push(`${significand[index++]}`);
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
// Exponent
|
|
738
|
+
string.push('E');
|
|
739
|
+
if (scientific_exponent > 0) {
|
|
740
|
+
string.push('+' + scientific_exponent);
|
|
741
|
+
} else {
|
|
742
|
+
string.push(`${scientific_exponent}`);
|
|
743
|
+
}
|
|
744
|
+
} else {
|
|
745
|
+
// Regular format with no decimal place
|
|
746
|
+
if (exponent >= 0) {
|
|
747
|
+
for (let i = 0; i < significand_digits; i++) {
|
|
748
|
+
string.push(`${significand[index++]}`);
|
|
749
|
+
}
|
|
750
|
+
} else {
|
|
751
|
+
let radix_position = significand_digits + exponent;
|
|
752
|
+
|
|
753
|
+
// non-zero digits before radix
|
|
754
|
+
if (radix_position > 0) {
|
|
755
|
+
for (let i = 0; i < radix_position; i++) {
|
|
756
|
+
string.push(`${significand[index++]}`);
|
|
757
|
+
}
|
|
758
|
+
} else {
|
|
759
|
+
string.push('0');
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
string.push('.');
|
|
763
|
+
// add leading zeros after radix
|
|
764
|
+
while (radix_position++ < 0) {
|
|
765
|
+
string.push('0');
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
for (let i = 0; i < significand_digits - Math.max(radix_position - 1, 0); i++) {
|
|
769
|
+
string.push(`${significand[index++]}`);
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return string.join('');
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
toJSON(): Decimal128Extended {
|
|
778
|
+
return { $numberDecimal: this.toString() };
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
/** @internal */
|
|
782
|
+
toExtendedJSON(): Decimal128Extended {
|
|
783
|
+
return { $numberDecimal: this.toString() };
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
/** @internal */
|
|
787
|
+
static fromExtendedJSON(doc: Decimal128Extended): Decimal128 {
|
|
788
|
+
return Decimal128.fromString(doc.$numberDecimal);
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** @internal */
|
|
792
|
+
[Symbol.for('nodejs.util.inspect.custom')](): string {
|
|
793
|
+
return this.inspect();
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
inspect(): string {
|
|
797
|
+
return `Decimal128("${this.toString()}")`;
|
|
798
|
+
}
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
Object.defineProperty(Decimal128.prototype, '_bsontype', { value: 'Decimal128' });
|